

<!DOCTYPE html>
<html lang="zh-CN" data-default-color-scheme=&#34;auto&#34;>



<head>
  <meta charset="UTF-8">
  <link rel="apple-touch-icon" sizes="76x76" href="/img/favicon.ico">
  <link rel="icon" href="/img/favicon.ico">
  <meta name="viewport"
        content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, shrink-to-fit=no">
  <meta http-equiv="x-ua-compatible" content="ie=edge">
  
  <meta name="theme-color" content="#2f4154">
  <meta name="description" content="叶尘的技术升级小木屋">
  <meta name="author" content="叶尘">
  <meta name="keywords" content="">
  
  <title>SpringMVC - 叶尘的技术升级小木屋</title>

  <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/css/bootstrap.min.css" />


  <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/github-markdown-css@4.0.0/github-markdown.min.css" />
  <link  rel="stylesheet" href="/lib/hint/hint.min.css" />

  
    
    
      
      <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/highlight.js@10.7.2/styles/github-gist.min.css" />
    
  

  
    <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3.5.7/dist/jquery.fancybox.min.css" />
  



<!-- 主题依赖的图标库，不要自行修改 -->

<link rel="stylesheet" href="//at.alicdn.com/t/font_1749284_ba1fz6golrf.css">



<link rel="stylesheet" href="//at.alicdn.com/t/font_1736178_kmeydafke9r.css">


<link  rel="stylesheet" href="/css/main.css" />

<!-- 自定义样式保持在最底部 -->

  
<link rel="stylesheet" href="//cdn.jsdelivr.net/gh/bynotes/texiao/source/css/shubiao.css">
<link rel="stylesheet" href="//cdn.jsdelivr.net/gh/bynotes/texiao/source/css/gundongtiao.css">
<link rel="stylesheet" href="//cdn.jsdelivr.net/gh/bynotes/texiao/source/css/daziyanse.css">
<link rel="stylesheet" href="//cdn.jsdelivr.net/gh/bynotes/texiao/source/css/toubudaziji.css">
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/aplayer/dist/APlayer.min.css">



  <script id="fluid-configs">
    var Fluid = window.Fluid || {};
    var CONFIG = {"hostname":"www.yechen-blog.cn","root":"/","version":"1.8.11","typing":{"enable":true,"typeSpeed":70,"cursorChar":"_","loop":false},"anchorjs":{"enable":true,"element":"h1,h2,h3,h4,h5,h6","placement":"right","visible":"hover","icon":""},"progressbar":{"enable":true,"height_px":3,"color":"#29d","options":{"showSpinner":false,"trickleSpeed":100}},"copy_btn":true,"image_zoom":{"enable":true,"img_url_replace":["",""]},"toc":{"enable":true,"headingSelector":"h1,h2,h3,h4,h5,h6","collapseDepth":0},"lazyload":{"enable":true,"loading_img":"/img/loading.gif","onlypost":false,"offset_factor":2},"web_analytics":{"enable":false,"baidu":null,"google":null,"gtag":null,"tencent":{"sid":null,"cid":null},"woyaola":null,"cnzz":null,"leancloud":{"app_id":null,"app_key":null,"server_url":null}},"search_path":"/local-search.xml"};
  </script>
  <script  src="/js/utils.js" ></script>
  <script  src="/js/color-schema.js" ></script>
<meta name="generator" content="Hexo 5.4.0"></head>


<body>
  <header style="height: 70vh;">
    <nav id="navbar" class="navbar fixed-top  navbar-expand-lg navbar-dark scrolling-navbar">
  <div class="container">
    <a class="navbar-brand"
       href="/">&nbsp;<strong>YECHEN</strong>&nbsp;</a>

    <button id="navbar-toggler-btn" class="navbar-toggler" type="button" data-toggle="collapse"
            data-target="#navbarSupportedContent"
            aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
      <div class="animated-icon"><span></span><span></span><span></span></div>
    </button>

    <!-- Collapsible content -->
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav ml-auto text-center">
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/">
                <i class="iconfont icon-home-fill"></i>
                首页
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/categories/">
                <i class="iconfont icon-qrcode"></i>
                分类
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/tags/">
                <i class="iconfont icon-tags-fill"></i>
                标签
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/about/">
                <i class="iconfont icon-user-fill"></i>
                关于
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/playlist/">
                <i class="iconfont icon-music"></i>
                音乐
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item dropdown">
              <a class="nav-link dropdown-toggle" target="_self" role="button"
                 data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                <i class="iconfont icon-books"></i>
                链接
              </a>
              <div class="dropdown-menu" aria-labelledby="navbarDropdown">
                
                  
                  
                  
                  <a class="dropdown-item" target="_blank" rel="noopener" href="https://hexo.fluid-dev.com/">
                    
                    主题博客
                  </a>
                
                  
                  
                  
                  <a class="dropdown-item" target="_blank" rel="noopener" href="https://hexo.fluid-dev.com/docs/guide/">
                    
                    配置指南
                  </a>
                
                  
                  
                  
                  <a class="dropdown-item" target="_blank" rel="noopener" href="https://hexo.fluid-dev.com/docs/icon/">
                    
                    图标用法
                  </a>
                
                  
                  
                  
                  <a class="dropdown-item" target="_blank" rel="noopener" href="https://www.bilibili.com">
                    
                    哔哩哔哩
                  </a>
                
              </div>
            </li>
          
        
        
          <li class="nav-item" id="search-btn">
            <a class="nav-link" target="_self" data-toggle="modal" data-target="#modalSearch">&nbsp;<i
                class="iconfont icon-search"></i>&nbsp;</a>
          </li>
        
        
          <li class="nav-item" id="color-toggle-btn">
            <a class="nav-link" target="_self">&nbsp;<i
                class="iconfont icon-dark" id="color-toggle-icon"></i>&nbsp;</a>
          </li>
        
      </ul>
    </div>
  </div>
</nav>

    <div class="banner" id="banner" parallax=true
         style="background: url('/img/banner.jpg') no-repeat center center;
           background-size: cover;">
      <div class="full-bg-img">
        <div class="mask flex-center" style="background-color: rgba(0, 0, 0, 0.3)">
          <div class="page-header text-center fade-in-up">
            <span class="h2" id="subtitle" title="SpringMVC">
              
            </span>

            
              <div class="mt-3">
  
    <span class="post-meta mr-2">
      <i class="iconfont icon-author" aria-hidden="true"></i>
      叶尘
    </span>
  
  
    <span class="post-meta">
      <i class="iconfont icon-date-fill" aria-hidden="true"></i>
      <time datetime="2021-09-13 17:52" pubdate>
        星期一, 九月 13日 2021, 5:52 下午
      </time>
    </span>
  
</div>

<div class="mt-1">
  
    
    <span class="post-meta mr-2">
      <i class="iconfont icon-chart"></i>
      18.8k 字
    </span>
  

  
    
    <span class="post-meta mr-2">
      <i class="iconfont icon-clock-fill"></i>
      
      
      272
       分钟
    </span>
  

  
  
    
      <!-- LeanCloud 统计文章PV -->
      <span id="leancloud-page-views-container" class="post-meta" style="display: none">
        <i class="iconfont icon-eye" aria-hidden="true"></i>
        <span id="leancloud-page-views"></span> 次
      </span>
    
  
</div>

            
          </div>

          
        </div>
      </div>
    </div>
  </header>

  <main>
    
      

<div class="container-fluid nopadding-x">
  <div class="row nomargin-x">
    <div class="d-none d-lg-block col-lg-2"></div>
    <div class="col-lg-8 nopadding-x-md">
      <div class="container nopadding-x-md" id="board-ctn">
        <div class="py-5" id="board">
          <article class="post-content mx-auto">
            <!-- SEO header -->
            <h1 style="display: none">SpringMVC</h1>
            
            <div class="markdown-body">
              <h2 id="1-SpringMVC-概述"><a href="#1-SpringMVC-概述" class="headerlink" title="1. SpringMVC 概述"></a>1. SpringMVC 概述</h2><h3 id="1-1-SpringMVC-简介"><a href="#1-1-SpringMVC-简介" class="headerlink" title="1.1 SpringMVC 简介"></a>1.1 SpringMVC 简介</h3><blockquote>
<p>SpringMVC 是一个基于Java 的实现了 MVC 设计模式的请求驱动类型的轻量级 Web 框架，通过把 Model，View，Controller 分离，将 web 层进行职责解耦，把复杂的 web 应用分成逻辑清晰的几部分，简化开发，减少出错，方便组内开发人员之间的配合。</p>
</blockquote>
<ul>
<li><strong>Model（模型）</strong>：数据模型，<strong>提供要展示的数据</strong>。</li>
<li><strong>VIew（视图）</strong>：为用户呈现数据的<strong>页面</strong>。</li>
<li><strong>Controller（控制器）</strong>：接受用户请求，调用业务逻辑层产生合适的数据（Model），同时传递数据给视图层（View）呈现给用户，也就是说控制器做了个<strong>调度员</strong>的工作。</li>
</ul>
<h3 id="1-2-SpringMVC-优点"><a href="#1-2-SpringMVC-优点" class="headerlink" title="1.2 SpringMVC 优点"></a>1.2 SpringMVC 优点</h3><ul>
<li>基于 MVC 架构，功能分工明确，解耦合。</li>
<li>容易理解，上手快，使用简单。</li>
<li>作 为 Spring 框 架 一 部 分 ， 能 够 使 用 Spring 的 IoC 和 Aop 。 方 便 整 合 Strtus，MyBatis，Hiberate，JPA 等其他框架。</li>
<li>SpringMVC 强化注解的使用，在控制器，Service，Dao 都可以使用注解，方便灵活。</li>
<li>功能强大：RESTful、数据验证、格式化、本地化、主题等。</li>
</ul>
<h2 id="2-第一个-SpringMVC-项目"><a href="#2-第一个-SpringMVC-项目" class="headerlink" title="2. 第一个 SpringMVC 项目"></a>2. 第一个 SpringMVC 项目</h2><p><strong>Step00</strong>：创建 Maven 管理的 JavaWeb 项目，添加依赖</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-comment">&lt;!-- servlet 依赖 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>javax.servlet<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>javax.servlet-api<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>4.0.1<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">scope</span>&gt;</span>provided<span class="hljs-tag">&lt;/<span class="hljs-name">scope</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br><br><span class="hljs-comment">&lt;!-- jsp 依赖 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>javax.servlet.jsp<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>jsp-api<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>2.2<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br><br><span class="hljs-comment">&lt;!-- springmvc 依赖，包含了 spring 核心依赖 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-webmvc<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>5.3.8<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br></code></pre></td></tr></table></figure>

<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210717/image.4mmxodccz4i0.png" srcset="/img/loading.gif" lazyload alt="依赖列表"></p>
<p><strong>Step01：在 web.xml 文件中注册中央调度器 DispatcherServlet</strong></p>
<p>DispatcherServlet 对象在创建过程中会创建出 SpringMVC 容器对象，并将容器放入上下文域对象中。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs java">DispatcherServlet 在 init() 中 &#123;<br>    <span class="hljs-comment">//创建容器，读取配置文件</span><br>    WebApplicationContext ctx = <span class="hljs-keyword">new</span> ClassPathXmlApplicationContext(<span class="hljs-string">&quot;springmvc.xml&quot;</span>);<br>    <span class="hljs-comment">//把容器对象放入到 ServletContext 中</span><br>    getServletContext().setAttribute(key, ctx);<br>&#125;<br></code></pre></td></tr></table></figure>

<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-meta">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">web-app</span> <span class="hljs-attr">xmlns</span>=<span class="hljs-string">&quot;http://xmlns.jcp.org/xml/ns/javaee&quot;</span></span><br><span class="hljs-tag">         <span class="hljs-attr">xmlns:xsi</span>=<span class="hljs-string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span><br><span class="hljs-tag">         <span class="hljs-attr">xsi:schemaLocation</span>=<span class="hljs-string">&quot;http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd&quot;</span></span><br><span class="hljs-tag">         <span class="hljs-attr">version</span>=<span class="hljs-string">&quot;4.0&quot;</span>&gt;</span><br><br>    <span class="hljs-comment">&lt;!-- 注册中央调度器 DispatcherServlet --&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">servlet</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">servlet-name</span>&gt;</span>springmvc<span class="hljs-tag">&lt;/<span class="hljs-name">servlet-name</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">servlet-class</span>&gt;</span>org.springframework.web.servlet.DispatcherServlet<span class="hljs-tag">&lt;/<span class="hljs-name">servlet-class</span>&gt;</span><br><br>        <span class="hljs-comment">&lt;!-- 指定初始化是加载配置文件的路径 --&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">init-param</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">param-name</span>&gt;</span>contextConfigLocation<span class="hljs-tag">&lt;/<span class="hljs-name">param-name</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">param-value</span>&gt;</span>classpath:springmvc.xml<span class="hljs-tag">&lt;/<span class="hljs-name">param-value</span>&gt;</span><br>        <span class="hljs-tag">&lt;/<span class="hljs-name">init-param</span>&gt;</span><br><br>        <span class="hljs-tag">&lt;<span class="hljs-name">load-on-startup</span>&gt;</span>1<span class="hljs-tag">&lt;/<span class="hljs-name">load-on-startup</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">servlet</span>&gt;</span><br>    <br>    <span class="hljs-tag">&lt;<span class="hljs-name">servlet-mapping</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">servlet-name</span>&gt;</span>springmvc<span class="hljs-tag">&lt;/<span class="hljs-name">servlet-name</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">url-pattern</span>&gt;</span>/<span class="hljs-tag">&lt;/<span class="hljs-name">url-pattern</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">servlet-mapping</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">web-app</span>&gt;</span><br></code></pre></td></tr></table></figure>

<p>关于 <code>&lt;init-param&gt;</code> 标签：DispatcherServlet 初始化是会读取 SpringMVC 配置文件，文件的默认路径是 /WEB-INF/当前servlet的name-servlet.xml（当前即为：/WEB-INF/springmvc-servlet.xml），因此我们需要更改这个默认路径。</p>
<p>关于 <code>&lt;load-on-startup&gt;</code> 标签：DispatcherServlet 初始化需要在 Tomcat 启动后就创建，load-on-startup 表示 tomcat 启动后创建对象的顺序，值是一个大于等于 0 的整数，数值越小，tomcat 创建对象的时机越早。</p>
<p>关于 <code>&lt;url-pattern&gt; </code> 标签：可以使用两种值</p>
<ol>
<li>使用扩展名方式， 语法 *.xxxx , xxxx是自定义的扩展名。 常用的方式 *.do, *.action, *.mvc 等等</li>
<li>“/“，匹配所有的请求（不包括.jsp）；”/*“ 匹配所有的请求；（包括.jsp）[解释](###5.5 详细了解 url-pattern )</li>
</ol>
<p><strong>Step02：编写处理器 Handler</strong></p>
<p>编写一个类，继承 Controller 接口，实现 handleRequest() 方法</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">HelloController</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Controller</span> </span>&#123;<br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> ModelAndView <span class="hljs-title">handleRequest</span><span class="hljs-params">(HttpServletRequest request, HttpServletResponse response)</span> <span class="hljs-keyword">throws</span> Exception </span>&#123;<br>        <span class="hljs-comment">// 1.接受数据</span><br>        <span class="hljs-comment">// 2.处理数据</span><br>        <span class="hljs-comment">// 3.封装数据</span><br>        ModelAndView modelAndView = <span class="hljs-keyword">new</span> ModelAndView();<br>        <span class="hljs-comment">// 指定数据</span><br>        modelAndView.addObject(<span class="hljs-string">&quot;msg&quot;</span>, <span class="hljs-string">&quot;Hello SpringMVC&quot;</span>);<br>        <span class="hljs-comment">// 指定视图（因为之后会在配置文件中视图解析器，所以这里直接写上视图名称即可）</span><br>        <span class="hljs-comment">// 框架会使用视图解析器中的指定的 前缀 + 视图名称 + 后缀，拼接出完整路径</span><br>        modelAndView.setViewName(<span class="hljs-string">&quot;hello&quot;</span>);<br>        <span class="hljs-comment">/*</span><br><span class="hljs-comment">            4、返回结果</span><br><span class="hljs-comment">            之后会将数据一个个放入 request 域中，即 request.setAttribute(key, value);</span><br><span class="hljs-comment">            将视图请求转发，即 request.getRequestDispatcher(&quot;路径&quot;).forward(request, response);</span><br><span class="hljs-comment">         */</span><br>        <span class="hljs-keyword">return</span> modelAndView;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p><code>ModelAndView</code>：表示本次请求的处理结果</p>
<ul>
<li>Model：数据，请求处理完成之后，要显示给用户的数据</li>
<li>View：视图，响应的页面，如 jsp 等</li>
</ul>
<p><strong>Step03：创建 SpringMVC 配置文件 springmvc.xml</strong></p>
<p>在 springmvc.xml 文件中配置 Handler，处理器映射器，处理器适配器，以及视图解析器</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-comment">&lt;!-- 配置 Handler --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;/hello.do&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;cn.yechen.controller.HelloController&quot;</span>/&gt;</span><br><br><span class="hljs-comment">&lt;!-- 配置处理器映射器 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping&quot;</span>/&gt;</span><br><br><span class="hljs-comment">&lt;!-- 配置处理器适配器 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter&quot;</span>/&gt;</span><br><br><span class="hljs-comment">&lt;!-- 声明视图解析器 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;org.springframework.web.servlet.view.InternalResourceViewResolver&quot;</span>&gt;</span><br>    <span class="hljs-comment">&lt;!-- 设置前缀：视图文件的路径，注意路径前后都有 / --&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;prefix&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;/WEB-INF/view/&quot;</span>/&gt;</span><br>    <span class="hljs-comment">&lt;!-- 设置后缀：视图文件的扩展名 --&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;suffix&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;.jsp&quot;</span>/&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">bean</span>&gt;</span><br></code></pre></td></tr></table></figure>

<blockquote>
<p>注：处理器映射器，处理器适配器，以及视图解析器也可以不创建，SpringMVC 给我们提供了一个 DispatcherServlet.properties 文件。系统会首先加载这里面的配置，如果我们没有配置，那么就默认使用这个文件的配置；如果我们配置了，那么就优先使用我们手动配置的。</p>
<p>处理器适配器默认：org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter</p>
<p>处理器映射器默认：org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping</p>
<p>视图解析器默认：org.springframework.web.servlet.view.InternalResourceViewResolver</p>
</blockquote>
<p><strong>Step04：编写发送请求（index.jsp）和显示请求结果的页面（hello.jsp）</strong></p>
<p>index.jsp</p>
<figure class="highlight jsp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs jsp">&lt;%@ page contentType=<span class="hljs-string">&quot;text/html;charset=UTF-8&quot;</span> language=<span class="hljs-string">&quot;java&quot;</span> %&gt;<br>&lt;html&gt;<br>&lt;head&gt;<br>    &lt;title&gt;Title&lt;/title&gt;<br>&lt;/head&gt;<br>&lt;body&gt;<br>&lt;p&gt;第一个springmvc项目&lt;/p&gt;<br>&lt;p&gt;&lt;a href=<span class="hljs-string">&quot;hello.do&quot;</span>&gt;发起hello.<span class="hljs-keyword">do</span>的请求&lt;/a&gt; &lt;/p&gt;<br>&lt;/body&gt;<br>&lt;/html&gt;<br></code></pre></td></tr></table></figure>

<p>WEB-INF/view/hello.jsp</p>
<figure class="highlight jsp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs jsp">&lt;%@ page contentType=<span class="hljs-string">&quot;text/html;charset=UTF-8&quot;</span> language=<span class="hljs-string">&quot;java&quot;</span> %&gt;<br>&lt;html&gt;<br>&lt;head&gt;<br>    &lt;title&gt;Hello&lt;/title&gt;<br>&lt;/head&gt;<br>&lt;body&gt;<br>&lt;h3&gt;msg数据：$&#123;msg&#125;&lt;/h3&gt;&lt;br/&gt;<br>&lt;/body&gt;<br>&lt;/html&gt;<br></code></pre></td></tr></table></figure>

<p><strong>Step05：启动 Tomcat，测试</strong></p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210717/image.7csih3e1p980.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p><a target="_blank" rel="noopener" href="https://www.cnblogs.com/ysocean/p/7375405.html">详细的其他配置</a></p>
<h2 id="3-SpringMVC-执行流程"><a href="#3-SpringMVC-执行流程" class="headerlink" title="3. SpringMVC 执行流程"></a>3. SpringMVC 执行流程</h2><h3 id="3-1-SpringMVC-组件及作用"><a href="#3-1-SpringMVC-组件及作用" class="headerlink" title="3.1 SpringMVC 组件及作用"></a>3.1 SpringMVC 组件及作用</h3><ol>
<li><strong>DispatcherServlet</strong>（中央控制器 / 前端控制器）：在创建时会读取 SpringMVC 配置文件，创建 SpringMVC 容器，作用有接受请求，响应结果，相当于转发器，中央处理器，有 了 DispatcherServlet，减少了其他组件之间的耦合度。</li>
<li><strong>HandlerMapping</strong>（处理器映射器）：根据请求的 URL，找到对应的 处理器对象（<code>Object handler</code>），并返回处理器执行链对象（<code>HandlerExecutionChain</code>）给 DispatcherServlet。SpringMVC 提供了多种不同的映射器实现不同的映射方式，例如：配置文件方式，实现接口方式，注解方式等。</li>
<li><strong>HandlerExecutionChain</strong>：处理器执行链，保存了处理器引射器找到的处理器对象（<code>Object handler</code>），和项目中的有拦截器，以集合方式保存（<code>List&lt;HandlerInterceptor&gt; interceptorList</code>）。</li>
<li><strong>HandlerAdapter</strong>（处理器适配器）：将各种 Controller 适配成 DispatcherServlet 可以使用的 Handler，通过特定规则（HandlerAdapter 要求的规则）去执行 Handler。通过 HandlerAdapter 对处理器进行执行，这是适配器模式的应用，通过扩展适配器可以对更多类型的处理器进行执行。</li>
<li><strong>Handler</strong>（处理器 / 控制器）：<strong>需要程序员编写</strong>，编写 Handler 时需要按照 HandlerAdapter 的要求去做，这样HandlerAdapter 才可以正确执行 Handler。Handler 是继 DispatcherServlet 前端控制器的<strong>后台控制器</strong>，在DispatcherServlet 控制下对用户请求进行处理，Handler 涉及业务需求，所以需要工程师针对用户需求进行开发，最终返回业务数据。</li>
<li><strong>ViewResolver</strong>（视图解析器）：进行视图解析，根据逻辑视图名解析成真正的视图 View。ViewResolver 负责将处理结果生成 View 视图，ViewResolver 首先根据逻辑视图名解析成具体的<strong>页面地址</strong>，然后对 <strong>View 进行渲染</strong>，将处理结果通过页面展示给用户。SpringMVC 提供了很多类型 View 视图，包括：jstlView、freemarkerView、pdfView、jsp、html 等。</li>
<li><strong>View</strong>（视图）：<strong>需要程序员编写</strong>，View 是一个接口，实现类支持不同的类型（jsp、html、freemarker、pdf等）</li>
</ol>
<h3 id="3-2-SpringMVC执行流程"><a href="#3-2-SpringMVC执行流程" class="headerlink" title="3.2 SpringMVC执行流程"></a>3.2 SpringMVC执行流程</h3><p>（1）用户发送请求至前端控制器 DispatcherServlet。</p>
<p>（2）DispatcherServlet 收到请求之后，调用处理器映射器 HandlerMapping，请求获取 Handler。</p>
<p>（3）处理器映射器根据请求的 URI 找到具体的处理器 Handler， 生成处理器对象及处理器拦截器（如果有则生成），一并返回到 DispatcherServlet。</p>
<p>（4）DispatcherServlet 调用处理器适配器 HandlerAdapter，请求执行 Handler。</p>
<p>（5）HandlerAdapter 进过适配调用，具体处理器 Handler 开始处理业务逻辑。</p>
<p>（6）Handler 执行完成返回 ModelAndView 对象到 HandlerAdapter。</p>
<p>（7）HandlerAdapter 将 Handler 的执行结果 ModelAndView 返回到 DispatcherServlet。</p>
<p>（8）DispatcherServlet 将 ModelAndView 传给视图解析器 ViewResolve 进行解析。</p>
<p>（9）ViewResolve 解析 ModelAndView 后将具体的 View 对象返回给 DispatcherServlet。</p>
<p>（10）DispatcherServlet 对返回的 View 进行渲染视图，即将模型数据填充值视图。</p>
<p>（11）DispatcherServlet 将视图响应给用户。</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210717/20180708224853769.4o539igoso40.png" srcset="/img/loading.gif" lazyload alt="20180708224853769"></p>
<p><img src="../../../AppData/Roaming/Typora/typora-user-images/image-20210717172929063.png" srcset="/img/loading.gif" lazyload alt="image-20210717172929063"></p>
<p>上图来源于  <a target="_blank" rel="noopener" href="http://www.coderead.cn/p/spring/map/file/Mvc%E6%97%B6%E5%BA%8F%E5%9B%BE.svg">源码阅读网</a></p>
<h2 id="4-使用注解简化开发"><a href="#4-使用注解简化开发" class="headerlink" title="4. 使用注解简化开发"></a>4. 使用注解简化开发</h2><p>虽然通过 SpringMVC 已经简化了一部分的开发，但是还不够，比如每次发送一个请求都要在后台对应创建一个控制器，还要在 springmvc 配置文件中配置请求路径，将控制器注册到容器中，这还是不方便，于是注解式开发出现了。</p>
<p>所谓 SpringMVC 的注解式开发是指，在代码中通过对类与方法的注解，便可完成处理器在 springmvc 容器的注册。注解式开发是重点。</p>
<p>web.xml 与之前没有差别</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-meta">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">web-app</span> <span class="hljs-attr">xmlns</span>=<span class="hljs-string">&quot;http://xmlns.jcp.org/xml/ns/javaee&quot;</span></span><br><span class="hljs-tag">         <span class="hljs-attr">xmlns:xsi</span>=<span class="hljs-string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span><br><span class="hljs-tag">         <span class="hljs-attr">xsi:schemaLocation</span>=<span class="hljs-string">&quot;http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd&quot;</span></span><br><span class="hljs-tag">         <span class="hljs-attr">version</span>=<span class="hljs-string">&quot;4.0&quot;</span>&gt;</span><br><br>    <span class="hljs-comment">&lt;!-- 注册中央调度器 DispatcherServlet --&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">servlet</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">servlet-name</span>&gt;</span>springmvc<span class="hljs-tag">&lt;/<span class="hljs-name">servlet-name</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">servlet-class</span>&gt;</span>org.springframework.web.servlet.DispatcherServlet<span class="hljs-tag">&lt;/<span class="hljs-name">servlet-class</span>&gt;</span><br><br>        <span class="hljs-tag">&lt;<span class="hljs-name">init-param</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">param-name</span>&gt;</span>contextConfigLocation<span class="hljs-tag">&lt;/<span class="hljs-name">param-name</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">param-value</span>&gt;</span>classpath:springmvc.xml<span class="hljs-tag">&lt;/<span class="hljs-name">param-value</span>&gt;</span><br>        <span class="hljs-tag">&lt;/<span class="hljs-name">init-param</span>&gt;</span><br><br>        <span class="hljs-tag">&lt;<span class="hljs-name">load-on-startup</span>&gt;</span>1<span class="hljs-tag">&lt;/<span class="hljs-name">load-on-startup</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">servlet</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">servlet-mapping</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">servlet-name</span>&gt;</span>springmvc<span class="hljs-tag">&lt;/<span class="hljs-name">servlet-name</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">url-pattern</span>&gt;</span>/<span class="hljs-tag">&lt;/<span class="hljs-name">url-pattern</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">servlet-mapping</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">web-app</span>&gt;</span><br></code></pre></td></tr></table></figure>

<p>修改配置文件 springmvc.xml</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-meta">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">beans</span> <span class="hljs-attr">xmlns</span>=<span class="hljs-string">&quot;http://www.springframework.org/schema/beans&quot;</span></span><br><span class="hljs-tag">       <span class="hljs-attr">xmlns:xsi</span>=<span class="hljs-string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span><br><span class="hljs-tag">       <span class="hljs-attr">xmlns:context</span>=<span class="hljs-string">&quot;http://www.springframework.org/schema/context&quot;</span></span><br><span class="hljs-tag">       <span class="hljs-attr">xsi:schemaLocation</span>=<span class="hljs-string">&quot;http://www.springframework.org/schema/beans</span></span><br><span class="hljs-string"><span class="hljs-tag">        https://www.springframework.org/schema/beans/spring-beans.xsd</span></span><br><span class="hljs-string"><span class="hljs-tag">        http://www.springframework.org/schema/context</span></span><br><span class="hljs-string"><span class="hljs-tag">        https://www.springframework.org/schema/context/spring-context.xsd&quot;</span>&gt;</span><br><br>    <span class="hljs-comment">&lt;!-- 开启注解扫描 --&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">context:component-scan</span> <span class="hljs-attr">base-package</span>=<span class="hljs-string">&quot;cn.yechen.controller&quot;</span>/&gt;</span><br><br>    <span class="hljs-comment">&lt;!-- 声明视图解析器，帮助开发人员设置视图文件的路径 --&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;org.springframework.web.servlet.view.InternalResourceViewResolver&quot;</span>&gt;</span><br>        <span class="hljs-comment">&lt;!-- 设置前缀：视图文件的路径，注意路径前后都有 / --&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;prefix&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;/WEB-INF/view/&quot;</span>/&gt;</span><br>        <span class="hljs-comment">&lt;!-- 设置后缀：视图文件的扩展名 --&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;suffix&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;.jsp&quot;</span>/&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">bean</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">beans</span>&gt;</span><br></code></pre></td></tr></table></figure>

<p>修改处理器类，使用 <code>@Controller</code> 注解，将类配置到 springmvc 容器中</p>
<p>使用 <code>@RequestMapping</code> 注解指定请求 URI 路径</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-comment">/*</span><br><span class="hljs-comment">    @Controller 创建处理器对象（声明 bean），对象放在 springmvc 容器中，可以处理请求</span><br><span class="hljs-comment">    能处理请求的都是控制器（处理器），MyController 能处器理请求，叫做后端控制器（back controller）</span><br><span class="hljs-comment"> */</span><br><span class="hljs-meta">@Controller</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyController</span> </span>&#123;<br>    <span class="hljs-comment">/*</span><br><span class="hljs-comment">        自定义方法处理用户提交的请求（类似 Servlet 中的 doGet, doPost 方法）</span><br><span class="hljs-comment"></span><br><span class="hljs-comment">        @RequestMapping 为请求映射，value 属性是是请求的 uri 地址，是一个数组，可以对应多个请求地址</span><br><span class="hljs-comment">        作用是将请求地址和对应处理方法绑定在一起，一个请求指定一方法，一个方法可以有多个请求</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-meta">@RequestMapping(value = &#123;&quot;/some.do&quot;&#125;)</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> ModelAndView <span class="hljs-title">doSome</span><span class="hljs-params">()</span> </span>&#123;<br>        <span class="hljs-comment">// 1.接受数据</span><br>        <span class="hljs-comment">// 2.处理数据</span><br>        <span class="hljs-comment">// 3.封装数据</span><br>        ModelAndView modelAndView = <span class="hljs-keyword">new</span> ModelAndView();<br>        <span class="hljs-comment">// 指定数据</span><br>        modelAndView.addObject(<span class="hljs-string">&quot;msg&quot;</span>, <span class="hljs-string">&quot;Hello SpringMVC Annotations&quot;</span>);<br>        modelAndView.addObject(<span class="hljs-string">&quot;fun&quot;</span>, <span class="hljs-string">&quot;执行 doSome 方法&quot;</span>);<br>        <span class="hljs-comment">// 指定视图</span><br>        modelAndView.setViewName(<span class="hljs-string">&quot;some&quot;</span>)；<br>        <span class="hljs-comment">// 4.返回结果    </span><br>        <span class="hljs-keyword">return</span> modelAndView;<br>    &#125;<br><br>    <span class="hljs-comment">// 处理另外的请求</span><br>    <span class="hljs-meta">@RequestMapping(value = &#123;&quot;/other.do&quot;,&quot;/second.do&quot;&#125;)</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> ModelAndView <span class="hljs-title">doOther</span><span class="hljs-params">()</span></span>&#123;<br>        ModelAndView mv  = <span class="hljs-keyword">new</span> ModelAndView();<br>        mv.addObject(<span class="hljs-string">&quot;msg&quot;</span>,<span class="hljs-string">&quot;====Hello SpringMVC Annotations====&quot;</span>);<br>        mv.addObject(<span class="hljs-string">&quot;fun&quot;</span>,<span class="hljs-string">&quot;执行的是 doOther 方法&quot;</span>);<br>        mv.setViewName(<span class="hljs-string">&quot;other&quot;</span>);<br>        <span class="hljs-keyword">return</span> mv;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>请求页 index.jsp</p>
<figure class="highlight jsp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs jsp">&lt;%@ page contentType=<span class="hljs-string">&quot;text/html;charset=UTF-8&quot;</span> language=<span class="hljs-string">&quot;java&quot;</span> %&gt;<br>&lt;html&gt;<br>&lt;head&gt;<br>    &lt;title&gt;Title&lt;/title&gt;<br>&lt;/head&gt;<br>&lt;body&gt;<br>    &lt;p&gt;第一个springmvc项目&lt;/p&gt;<br>    &lt;p&gt;&lt;a href=<span class="hljs-string">&quot;some.do&quot;</span>&gt;发起some.<span class="hljs-keyword">do</span>的请求&lt;/a&gt; &lt;/p&gt;<br>    &lt;p&gt;&lt;a href=<span class="hljs-string">&quot;other.do&quot;</span>&gt;发起other.<span class="hljs-keyword">do</span>的请求&lt;/a&gt; &lt;/p&gt;<br>&lt;/body&gt;<br>&lt;/html&gt;<br></code></pre></td></tr></table></figure>

<p>响应页 WEB-INF/view/some.jsp</p>
<figure class="highlight jsp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs jsp">&lt;%@ page contentType=<span class="hljs-string">&quot;text/html;charset=UTF-8&quot;</span> language=<span class="hljs-string">&quot;java&quot;</span> %&gt;<br>&lt;html&gt;<br>&lt;head&gt;<br>    &lt;title&gt;Title&lt;/title&gt;<br>&lt;/head&gt;<br>&lt;body&gt;<br>&lt;h3&gt;/WEB-INF/view/some.jsp 从 request 作用域获取数据&lt;/h3&gt;&lt;br/&gt;<br>&lt;h3&gt;msg数据：$&#123;msg&#125;&lt;/h3&gt;&lt;br/&gt;<br>&lt;h3&gt;fun数据：$&#123;fun&#125;&lt;/h3&gt;<br>&lt;/body&gt;<br>&lt;/html&gt;<br></code></pre></td></tr></table></figure>

<p>响应页 WEB-INF/view/other.jsp</p>
<figure class="highlight jsp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs jsp">&lt;%@ page contentType=<span class="hljs-string">&quot;text/html;charset=UTF-8&quot;</span> language=<span class="hljs-string">&quot;java&quot;</span> %&gt;<br>&lt;html&gt;<br>&lt;head&gt;<br>    &lt;title&gt;Title&lt;/title&gt;<br>&lt;/head&gt;<br>&lt;body&gt;<br>&lt;h3&gt;/WEB-INF/view/other.jsp从request作用域获取数据&lt;/h3&gt;&lt;br/&gt;<br>&lt;h3&gt;msg数据：$&#123;msg&#125;&lt;/h3&gt;&lt;br/&gt;<br>&lt;h3&gt;fun数据：$&#123;fun&#125;&lt;/h3&gt;<br>&lt;/body&gt;<br>&lt;/html&gt;<br></code></pre></td></tr></table></figure>

<p>测试：</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210717/image.5rftkn8vgb40.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210717/image.1127bfvbfx40.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210717/image.touc8sbtz1c.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<h2 id="5-SpringMVC-注解式开发"><a href="#5-SpringMVC-注解式开发" class="headerlink" title="5. SpringMVC 注解式开发"></a>5. SpringMVC 注解式开发</h2><h3 id="5-1-Controller-注解"><a href="#5-1-Controller-注解" class="headerlink" title="5.1 @Controller 注解"></a>5.1 @Controller 注解</h3><p>@Controller 创建处理器对象（声明 bean），对象放在 springmvc 容器中，可以处理请求</p>
<p>能处理请求的都是控制器（处理器），MyController 能处器理请求，叫做后端控制器（back controller）</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Controller</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyCotroller</span> </span>&#123;<br>    <br>&#125;<br></code></pre></td></tr></table></figure>



<h3 id="5-2-RequestMapping-注解"><a href="#5-2-RequestMapping-注解" class="headerlink" title="5.2 @RequestMapping 注解"></a>5.2 @RequestMapping 注解</h3><p>通过 <code>@RequestMapping</code>  注解可以定义处理器对于请求的映射规则。</p>
<p>该注解可以注解在方法上，也可以注解在类上，但意义是不同的。value 属性值常以“/”开始。</p>
<p><strong>@RequestMapping 的 value 属性用于定义所匹配请求的 URI</strong>。但对于注解在方法上与类上，其 value 属性所指定的 URI，意义是不同的。</p>
<ul>
<li>一个 @Controller 所注解的类中，可以定义多个处理器方法。当然，不同的处理器方法所匹配的 URI 是不同的。这些不同的 URI 被指定在注解于方法之上的 @RequestMapping 的 value 属性中。</li>
<li>但若这些请求具有相同的 URI 部分，则这些相同的 URI，可以被抽取到注解在类之上的@RequestMapping 的 value 属性中。此时的这个 URI 表示模块的名称。</li>
<li>URI 的请求是相对于 Web 的根目录。换个角度说，要访问处理器的指定方法，必须要在方法指定 URI 之前加上处理器类前定义的模块名称。</li>
</ul>
<p>如：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Controller</span><br><span class="hljs-comment">/*</span><br><span class="hljs-comment">    @RequestMapping 放到类上面时，value 表示所有请求地址的公共部分，叫做模块名称</span><br><span class="hljs-comment">    放到方法上时，表示当前请求的具体功能</span><br><span class="hljs-comment">    类上路径和方法上路径组合在一起，就是这个请求路径的 URI 了</span><br><span class="hljs-comment"> */</span><br><span class="hljs-meta">@RequestMapping(&quot;/test&quot;)</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyController</span> </span>&#123;<br>    <br>    <span class="hljs-meta">@RequestMapping(value = &quot;/some.do&quot;)</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> ModelAndView <span class="hljs-title">doSome</span><span class="hljs-params">()</span> </span>&#123;<br>        ModelAndView modelAndView = <span class="hljs-keyword">new</span> ModelAndView();<br>        modelAndView.addObject(<span class="hljs-string">&quot;msg&quot;</span>, <span class="hljs-string">&quot;测试 @RequestMapping&quot;</span>);<br>        modelAndView.addObject(<span class="hljs-string">&quot;method&quot;</span>, <span class="hljs-string">&quot;some.do&quot;</span>);<br>        modelAndView.setViewName(<span class="hljs-string">&quot;show&quot;</span>);<br>        <span class="hljs-keyword">return</span> modelAndView;<br>    &#125;<br>    <br>    <span class="hljs-meta">@RequestMapping(value = &quot;/other.do&quot;)</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> ModelAndView <span class="hljs-title">doOther</span><span class="hljs-params">()</span> </span>&#123;<br>        ModelAndView modelAndView = <span class="hljs-keyword">new</span> ModelAndView();<br>        modelAndView.addObject(<span class="hljs-string">&quot;msg&quot;</span>, <span class="hljs-string">&quot;测试 @RequestMapping&quot;</span>);<br>        modelAndView.addObject(<span class="hljs-string">&quot;method&quot;</span>, <span class="hljs-string">&quot;other.do&quot;</span>);<br>        modelAndView.setViewName(<span class="hljs-string">&quot;show2&quot;</span>);<br>        <span class="hljs-keyword">return</span> modelAndView;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>此时需要调用 doSome() 这个方法，请求路径的 URI 就是 /test/some.do 了</p>
<p><strong>@RequestMapping 还可以指定请求提交的方式</strong></p>
<p>@RequestMapping 有一个属性 method，表示请求的方式，它的值是 RequestMethod 类的枚举值，可以设置不同的请求方式。以下是 RequestMethod  类源码：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">enum</span> <span class="hljs-title">RequestMethod</span> </span>&#123;<br>    GET,<br>    HEAD,<br>    POST,<br>    PUT,<br>    PATCH,<br>    DELETE,<br>    OPTIONS,<br>    TRACE;<br><br>    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-title">RequestMethod</span><span class="hljs-params">()</span> </span>&#123;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>如：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Controller</span><br><span class="hljs-meta">@RequestMapping(&quot;/test&quot;)</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyController</span> </span>&#123;<br><br><br>    <span class="hljs-comment">// 当 method 没有设置的时候，请求方式是不受限制的</span><br>    <span class="hljs-meta">@RequestMapping(value = &quot;/some.do&quot;)</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> ModelAndView <span class="hljs-title">doSome</span><span class="hljs-params">()</span> </span>&#123;<br>        ModelAndView modelAndView = <span class="hljs-keyword">new</span> ModelAndView();<br>        modelAndView.addObject(<span class="hljs-string">&quot;msg&quot;</span>, <span class="hljs-string">&quot;测试 @RequestMapping&quot;</span>);<br>        modelAndView.addObject(<span class="hljs-string">&quot;method&quot;</span>, <span class="hljs-string">&quot;some.do&quot;</span>);<br>        modelAndView.setViewName(<span class="hljs-string">&quot;show&quot;</span>);<br>        <span class="hljs-keyword">return</span> modelAndView;<br>    &#125;<br><br>    <span class="hljs-comment">// 指定请求方式是 POST 方式</span><br>    <span class="hljs-meta">@RequestMapping(value = &quot;/other.do&quot;, method = RequestMethod.POST)</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> ModelAndView <span class="hljs-title">doOther</span><span class="hljs-params">()</span> </span>&#123;<br>        ModelAndView modelAndView = <span class="hljs-keyword">new</span> ModelAndView();<br>        modelAndView.addObject(<span class="hljs-string">&quot;msg&quot;</span>, <span class="hljs-string">&quot;测试 @RequestMapping&quot;</span>);<br>        modelAndView.addObject(<span class="hljs-string">&quot;method&quot;</span>, <span class="hljs-string">&quot;other.do&quot;</span>);<br>        modelAndView.setViewName(<span class="hljs-string">&quot;show2&quot;</span>);<br>        <span class="hljs-keyword">return</span> modelAndView;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>当然 SpringMVC 还提供了一些类似 @RequestMapping 的注解，只是已经指定好了请求方法</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@GetMapping</span><br><span class="hljs-meta">@PostMapping</span><br><span class="hljs-meta">@PutMapping</span><br><span class="hljs-meta">@DeleteMapping</span><br>......<br></code></pre></td></tr></table></figure>



<h3 id="5-3-处理器方法的参数"><a href="#5-3-处理器方法的参数" class="headerlink" title="5.3 处理器方法的参数"></a>5.3 处理器方法的参数</h3><p>处理器方法可以包含以下四类参数，这些参数会在系统调用时由系统自动赋值，即程序员可在方法内直接使用。</p>
<ul>
<li>HttpServletRequest</li>
<li>HttpServletResponse</li>
<li>HttpSession</li>
<li>请求中所携带的请求参数</li>
</ul>
<h4 id="5-3-1-接收-HttpServletRequest、HttpServletResponse、HttpSession"><a href="#5-3-1-接收-HttpServletRequest、HttpServletResponse、HttpSession" class="headerlink" title="5.3.1 接收 HttpServletRequest、HttpServletResponse、HttpSession"></a>5.3.1 接收 HttpServletRequest、HttpServletResponse、HttpSession</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Controller</span><br><span class="hljs-meta">@RequestMapping(&quot;/test&quot;)</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ParameterController</span> </span>&#123;<br>    <span class="hljs-comment">/*</span><br><span class="hljs-comment">        方法形参可以携带</span><br><span class="hljs-comment">            HttpServletRequest、</span><br><span class="hljs-comment">            HttpServletResponse、</span><br><span class="hljs-comment">            HttpSession、</span><br><span class="hljs-comment">            请求中所携带的参数</span><br><span class="hljs-comment">        这些参数会在系统调用时由系统自动赋值，可以在方法上直接使用</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-comment">// 测试：请求路径 /test/1.do?name=&quot;yechen&quot;</span><br>    <span class="hljs-meta">@RequestMapping(&quot;/1.do&quot;)</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> ModelAndView <span class="hljs-title">test1</span><span class="hljs-params">(HttpServletRequest request, HttpServletResponse response, HttpSession session)</span> </span>&#123;<br>        ModelAndView modelAndView = <span class="hljs-keyword">new</span> ModelAndView();<br>        modelAndView.addObject(<span class="hljs-string">&quot;msg&quot;</span>, request.getParameter(<span class="hljs-string">&quot;name&quot;</span>));<br>        modelAndView.setViewName(<span class="hljs-string">&quot;showParameter&quot;</span>);<br>        <span class="hljs-keyword">return</span> modelAndView;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>展示页面 showParameter.jsp</p>
<figure class="highlight jsp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs jsp">&lt;%@ page contentType=<span class="hljs-string">&quot;text/html;charset=UTF-8&quot;</span> language=<span class="hljs-string">&quot;java&quot;</span> %&gt;<br>&lt;html&gt;<br>&lt;head&gt;<br>    &lt;title&gt;showParameter&lt;/title&gt;<br>&lt;/head&gt;<br>&lt;body&gt;<br>&lt;h2&gt;$&#123;msg&#125;&lt;/h2&gt;<br>&lt;/body&gt;<br>&lt;/html&gt;<br></code></pre></td></tr></table></figure>

<p>测试：</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210718/image.25g4f3fqj280.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p><img src="../../../AppData/Roaming/Typora/typora-user-images/image-20210718103236296.png" srcset="/img/loading.gif" lazyload alt="image-20210718103236296"></p>
<h4 id="5-3-2-逐个接受请求参数"><a href="#5-3-2-逐个接受请求参数" class="headerlink" title="5.3.2 逐个接受请求参数"></a>5.3.2 逐个接受请求参数</h4><p><strong>要求：</strong></p>
<p>处理器方法的形参名要和请求中参数名一致，同名的请求参数自动赋值给同名的形参如请求路径为 /test/2.do?name=yechen&amp;age=18，方法形参中有 name 属性就赋值 yechen，age 属性就赋值 18</p>
<p><strong>框架内部接收请求参数过程：</strong></p>
<ol>
<li><p>使用 request 对象接收请求参数<br>String strName = request.getParameter(“name”);<br>String strAge = request.getParameter(“age”);</p>
</li>
<li><p>SpringMVC 框架通过 DispatcherServlet 调用处理器的对应方法</p>
<p>调用方法时，按名称对应，把接收的参数赋值给形参<br>doSome（strName，Integer.valueOf(strAge)）<br>框架会提供类型转换的功能，能把 String 转为 int ，long ， float， double 等类型。</p>
</li>
</ol>
<p>如：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Controller</span><br><span class="hljs-meta">@RequestMapping(&quot;/test&quot;)</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ParameterController</span> </span>&#123;<br><br>    <span class="hljs-meta">@RequestMapping(&quot;/2.do&quot;)</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> ModelAndView <span class="hljs-title">test2</span><span class="hljs-params">(String name, <span class="hljs-keyword">int</span> age)</span> </span>&#123;<br>        <span class="hljs-comment">// 方法内部就可以直接使用这些参数，不用向 servlet 中一样一个个从 request 中获取参数了</span><br>        ModelAndView modelAndView = <span class="hljs-keyword">new</span> ModelAndView();<br>        modelAndView.addObject(<span class="hljs-string">&quot;msg&quot;</span>, <span class="hljs-string">&quot;name = &quot;</span>+name+<span class="hljs-string">&quot;，age = &quot;</span>+age);<br>        modelAndView.setViewName(<span class="hljs-string">&quot;showParameter&quot;</span>);<br>        <span class="hljs-keyword">return</span> modelAndView;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>编写前端请求表单 index.jsp</p>
<figure class="highlight jsp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><code class="hljs jsp">&lt;%@ page contentType=<span class="hljs-string">&quot;text/html;charset=UTF-8&quot;</span> language=<span class="hljs-string">&quot;java&quot;</span> %&gt;<br>&lt;html&gt;<br>&lt;head&gt;<br>    &lt;title&gt;index&lt;/title&gt;<br>&lt;/head&gt;<br>&lt;body&gt;<br>    &lt;form action=<span class="hljs-string">&quot;test/2.do&quot;</span> method=<span class="hljs-string">&quot;get&quot;</span>&gt;<br>        &lt;table&gt;<br>            &lt;tr&gt;<br>                &lt;td&gt;姓名&lt;/td&gt;<br>                &lt;td&gt; &lt;input type=<span class="hljs-string">&quot;text&quot;</span> name=<span class="hljs-string">&quot;name&quot;</span>&gt;&lt;/td&gt;<br>            &lt;/tr&gt;<br>            &lt;tr&gt;<br>                &lt;td&gt; 年龄&lt;/td&gt;<br>                &lt;td&gt;&lt;input type=<span class="hljs-string">&quot;text&quot;</span> name=<span class="hljs-string">&quot;age&quot;</span>&gt;&lt;/td&gt;<br>            &lt;/tr&gt;<br>            &lt;tr&gt;<br>                &lt;td&gt;&lt;/td&gt;<br>                &lt;td&gt;&lt;input type=<span class="hljs-string">&quot;submit&quot;</span> value=<span class="hljs-string">&quot;提交&quot;</span>&gt;&lt;/td&gt;<br>            &lt;/tr&gt;<br>        &lt;/table&gt;<br>    &lt;/form&gt;<br>&lt;/body&gt;<br>&lt;/html&gt;<br></code></pre></td></tr></table></figure>

<p>测试：</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210718/image.71278lfemd80.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p><strong>存在的问题1</strong>：在当前表单中没有在 age 栏中填入值，那么 age 的值就是“”，无法转换为方法中设置的 int 类型，就会报出 400 错误，<strong>400状态码是客户端错误， 表示提交请求参数过程中，发生了问题</strong>，这里就是类型转换出错。</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210718/image.dv4ojrgbpow.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p>同时控制台也会出现：</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210718/image.5ja79ke4r4w0.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p>解决方法：</p>
<ol>
<li>前端判断值，没有填或类型不对都都不能提交。</li>
<li>处理器方法中 age 类型改为包装类型 Integer 或直接 String</li>
</ol>
<p><strong>存在问题2</strong>：当表单提交中存在中文时，并且提交方式为 POST，显示存在乱码。</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210718/image.2w7sfsqukmi0.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210718/image.1ec5b821nw68.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p>解决方法：SpringMVC 对于请求参数中中文乱码的问题，给出了专门的字符过滤器 CharacterEncodingFilter，我可以在 web.xml 文件中注册过滤器，来直接使用它。当然也可以自己写一个过滤器。</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-comment">&lt;!-- 配置 SpringMVC 中自带的乱码过滤器 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">filter</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">filter-name</span>&gt;</span>encoding<span class="hljs-tag">&lt;/<span class="hljs-name">filter-name</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">filter-class</span>&gt;</span>org.springframework.web.filter.CharacterEncodingFilter<span class="hljs-tag">&lt;/<span class="hljs-name">filter-class</span>&gt;</span><br>    <span class="hljs-comment">&lt;!-- 设置项目使用的字符编码 --&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">init-param</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">param-name</span>&gt;</span>encoding<span class="hljs-tag">&lt;/<span class="hljs-name">param-name</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">param-value</span>&gt;</span>utf-8<span class="hljs-tag">&lt;/<span class="hljs-name">param-value</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">init-param</span>&gt;</span><br>    <span class="hljs-comment">&lt;!-- 强制请求对象（HttpServletRequest）使用 encoding 编码的值 --&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">init-param</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">param-name</span>&gt;</span>forceRequestEncoding<span class="hljs-tag">&lt;/<span class="hljs-name">param-name</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">param-value</span>&gt;</span>true<span class="hljs-tag">&lt;/<span class="hljs-name">param-value</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">init-param</span>&gt;</span><br>    <span class="hljs-comment">&lt;!-- 强制响应对象（HttpServletResponse）使用 encoding 编码的值 --&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">init-param</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">param-name</span>&gt;</span>forceResponseEncoding<span class="hljs-tag">&lt;/<span class="hljs-name">param-name</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">param-value</span>&gt;</span>true<span class="hljs-tag">&lt;/<span class="hljs-name">param-value</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">init-param</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">filter</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">filter-mapping</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">filter-name</span>&gt;</span>encoding<span class="hljs-tag">&lt;/<span class="hljs-name">filter-name</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">url-pattern</span>&gt;</span>/*<span class="hljs-tag">&lt;/<span class="hljs-name">url-pattern</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">filter-mapping</span>&gt;</span><br></code></pre></td></tr></table></figure>

<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210718/image.2w7sfsqukmi0.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210718/image.1l6lpfbedveo.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p>分析一下 CharacterEncodingFilter 中核心方法</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210718/image.1rq86ljw4f5s.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<h4 id="5-3-3-校正请求参数名-RequestParam"><a href="#5-3-3-校正请求参数名-RequestParam" class="headerlink" title="5.3.3 校正请求参数名@RequestParam"></a>5.3.3 校正请求参数名@RequestParam</h4><p>所谓校正请求参数名，是指若请求 URL 所携带的参数名称与处理方法中指定的参数名不相同时，则需在处理方法参数前，添加一个注解 @RequestParam (“请求参数名”)，指定请求 URL 所携带参数的名称。该注解是对处理器方法参数进行修饰的。value 属性指定请求参数的名称。</p>
<p>@RequestParam 只能使用在逐个接收参数的情况下。</p>
<p>例如请求页面表单</p>
<figure class="highlight jsp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs jsp">&lt;form action=<span class="hljs-string">&quot;test/3.do&quot;</span> method=<span class="hljs-string">&quot;get&quot;</span>&gt;<br>    &lt;table&gt;<br>        &lt;tr&gt;<br>            &lt;td&gt;姓名&lt;/td&gt;<br>            &lt;td&gt; &lt;input type=<span class="hljs-string">&quot;text&quot;</span> name=<span class="hljs-string">&quot;userName&quot;</span>&gt;&lt;/td&gt;<br>        &lt;/tr&gt;<br>        &lt;tr&gt;<br>            &lt;td&gt; 年龄&lt;/td&gt;<br>            &lt;td&gt;&lt;input type=<span class="hljs-string">&quot;text&quot;</span> name=<span class="hljs-string">&quot;userAge&quot;</span>&gt;&lt;/td&gt;<br>        &lt;/tr&gt;<br>        &lt;tr&gt;<br>            &lt;td&gt;&lt;/td&gt;<br>            &lt;td&gt;&lt;input type=<span class="hljs-string">&quot;submit&quot;</span> value=<span class="hljs-string">&quot;提交&quot;</span>&gt;&lt;/td&gt;<br>        &lt;/tr&gt;<br>    &lt;/table&gt;<br>&lt;/form&gt;<br></code></pre></td></tr></table></figure>

<p>处理方法</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@RequestMapping(&quot;/3.do&quot;)</span><br><span class="hljs-function"><span class="hljs-keyword">public</span> ModelAndView <span class="hljs-title">test3</span><span class="hljs-params">(String name, <span class="hljs-keyword">int</span> age)</span> </span>&#123;<br>    <span class="hljs-comment">// 方法内部就可以直接使用这些参数，不用向 servlet 中一样一个个从 request 中获取参数了</span><br>    ModelAndView modelAndView = <span class="hljs-keyword">new</span> ModelAndView();<br>    modelAndView.addObject(<span class="hljs-string">&quot;msg&quot;</span>, <span class="hljs-string">&quot;name = &quot;</span>+name+<span class="hljs-string">&quot;，age = &quot;</span>+age);<br>    modelAndView.setViewName(<span class="hljs-string">&quot;showParameter&quot;</span>);<br>    <span class="hljs-keyword">return</span> modelAndView;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>但此时请求的参数名方法形参的名称不一致，值是不能赋上的，因此可以使用 @RequestParam 注解在参数前面，value 属性指定请求参数名称，将请求参数和形参一一绑定，这样就可以对应赋值了。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@RequestMapping(&quot;/3.do&quot;)</span><br><span class="hljs-function"><span class="hljs-keyword">public</span> ModelAndView <span class="hljs-title">test3</span><span class="hljs-params">(<span class="hljs-meta">@RequestParam(&quot;userName&quot;)</span> String name, <span class="hljs-meta">@RequestParam(&quot;userAge&quot;)</span> <span class="hljs-keyword">int</span> age)</span> </span>&#123;<br>    <span class="hljs-comment">// 方法内部就可以直接使用这些参数，不用向 servlet 中一样一个个从 request 中获取参数了</span><br>    ModelAndView modelAndView = <span class="hljs-keyword">new</span> ModelAndView();<br>    modelAndView.addObject(<span class="hljs-string">&quot;msg&quot;</span>, <span class="hljs-string">&quot;name = &quot;</span>+name+<span class="hljs-string">&quot;，age = &quot;</span>+age);<br>    modelAndView.setViewName(<span class="hljs-string">&quot;showParameter&quot;</span>);<br>    <span class="hljs-keyword">return</span> modelAndView;<br>&#125;<br></code></pre></td></tr></table></figure>

<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210718/image.33q672lf3pa0.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p>@RequestParam 还有一个属性 required，是一个 boolean，表示请求中是否一定包包含该参数，默认值是 true，即在请求中一定要包含当前参数，请求参数不存在是，服务器会报出 400  错误。</p>
<p>当请求参数可以没有时，可以将当前参数的 required 属性设置为 false。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@RequestMapping(&quot;/3.do&quot;)</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> ModelAndView <span class="hljs-title">test3</span><span class="hljs-params">(<span class="hljs-meta">@RequestParam(value = &quot;userName&quot;, required = false)</span> String name, </span></span><br><span class="hljs-params"><span class="hljs-function">                              <span class="hljs-meta">@RequestParam(value = &quot;userAge&quot;, required = false)</span> <span class="hljs-keyword">int</span> age)</span> </span>&#123;<br><br>    &#125;<br></code></pre></td></tr></table></figure>



<h4 id="5-3-4-对象参数接收"><a href="#5-3-4-对象参数接收" class="headerlink" title="5.3.4 对象参数接收"></a>5.3.4 对象参数接收</h4><p>当接受的参数很多的时候，在方法中一个个写上形参很麻烦，此时就可以用对象来接收请求参数。</p>
<p>将处理器方法的参数定义为一个对象，只要保证请求参数名与这个对象的属性同名即可。</p>
<p>编写请求表单</p>
<figure class="highlight jsp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><code class="hljs jsp">对象接收参数<br>&lt;form action=<span class="hljs-string">&quot;test/4.do&quot;</span> method=<span class="hljs-string">&quot;get&quot;</span>&gt;<br>    &lt;table&gt;<br>        &lt;tr&gt;<br>            &lt;td&gt;姓名&lt;/td&gt;<br>            &lt;td&gt; &lt;input type=<span class="hljs-string">&quot;text&quot;</span> name=<span class="hljs-string">&quot;name&quot;</span>&gt;&lt;/td&gt;<br>        &lt;/tr&gt;<br>        &lt;tr&gt;<br>            &lt;td&gt; 年龄&lt;/td&gt;<br>            &lt;td&gt;&lt;input type=<span class="hljs-string">&quot;text&quot;</span> name=<span class="hljs-string">&quot;age&quot;</span>&gt;&lt;/td&gt;<br>        &lt;/tr&gt;<br>        &lt;tr&gt;<br>            &lt;td&gt; 邮箱&lt;/td&gt;<br>            &lt;td&gt;&lt;input type=<span class="hljs-string">&quot;text&quot;</span> name=<span class="hljs-string">&quot;email&quot;</span>&gt;&lt;/td&gt;<br>        &lt;/tr&gt;<br>        &lt;tr&gt;<br>            &lt;td&gt;&lt;/td&gt;<br>            &lt;td&gt;&lt;input type=<span class="hljs-string">&quot;submit&quot;</span> value=<span class="hljs-string">&quot;提交&quot;</span>&gt;&lt;/td&gt;<br>        &lt;/tr&gt;<br>    &lt;/table&gt;<br>&lt;/form&gt;<br></code></pre></td></tr></table></figure>

<p>定义一个 vo 类，用来接受参数</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span> </span>&#123;<br>    <span class="hljs-keyword">private</span> String name;<br>    <span class="hljs-keyword">private</span> Integer age;<br>    <span class="hljs-keyword">private</span> String email;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">User</span><span class="hljs-params">()</span> </span>&#123;<br>        System.out.println(<span class="hljs-string">&quot;User 的无参构造方法&quot;</span>);<br>    &#125;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">getName</span><span class="hljs-params">()</span> </span>&#123;<br>        <span class="hljs-keyword">return</span> name;<br>    &#125;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setName</span><span class="hljs-params">(String name)</span> </span>&#123;<br>        <span class="hljs-keyword">this</span>.name = name;<br>        System.out.println(<span class="hljs-string">&quot;User setName() 方法执行&quot;</span>);<br>    &#125;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> Integer <span class="hljs-title">getAge</span><span class="hljs-params">()</span> </span>&#123;<br>        <span class="hljs-keyword">return</span> age;<br>    &#125;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setAge</span><span class="hljs-params">(Integer age)</span> </span>&#123;<br>        <span class="hljs-keyword">this</span>.age = age;<br>        System.out.println(<span class="hljs-string">&quot;User setAge() 方法执行&quot;</span>);<br>    &#125;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">getEmail</span><span class="hljs-params">()</span> </span>&#123;<br>        <span class="hljs-keyword">return</span> email;<br>    &#125;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setEmail</span><span class="hljs-params">(String email)</span> </span>&#123;<br>        <span class="hljs-keyword">this</span>.email = email;<br>        System.out.println(<span class="hljs-string">&quot;User setEmail() 方法执行&quot;</span>);<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>编写处理器方法</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs java"> <span class="hljs-meta">@RequestMapping(&quot;/4.do&quot;)</span><br><span class="hljs-function"><span class="hljs-keyword">public</span> ModelAndView <span class="hljs-title">test4</span><span class="hljs-params">(User user)</span> </span>&#123;<br>    ModelAndView modelAndView = <span class="hljs-keyword">new</span> ModelAndView();<br>    modelAndView.addObject(<span class="hljs-string">&quot;msg&quot;</span>, <span class="hljs-string">&quot;name = &quot;</span>+user.getName()+<span class="hljs-string">&quot;，age = &quot;</span>+user.getAge()+<span class="hljs-string">&quot;，email = &quot;</span>+user.getEmail());<br>    modelAndView.setViewName(<span class="hljs-string">&quot;showParameter&quot;</span>);<br>    <span class="hljs-keyword">return</span> modelAndView;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>测试：</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210718/image.4p399yhjp5w0.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p>同时观察控制台</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210718/image.4jv3cholaj20.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p>表明 SpringMVC 在内部会通过 User 类的无参构造方法创建对象，并通过 set 方法为参数一个个赋值。</p>
<h3 id="5-4-处理器方法的返回值"><a href="#5-4-处理器方法的返回值" class="headerlink" title="5.4 处理器方法的返回值"></a>5.4 处理器方法的返回值</h3><p>使用 @Controller 注解的处理器的处理器方法，其返回值常用的有四种类型：</p>
<ol>
<li><p>ModelAndView</p>
</li>
<li><p>String</p>
</li>
<li><p>无返回值 void</p>
</li>
<li><p>返回自定义类型对象</p>
</li>
</ol>
<p>根据不同的情况，使用不同的返回值。</p>
<h4 id="5-4-1-返回-ModelAndView"><a href="#5-4-1-返回-ModelAndView" class="headerlink" title="5.4.1 返回 ModelAndView"></a>5.4.1 返回 ModelAndView</h4><p>若处理器方法处理完后，<strong>需要跳转到其它资源，且又要在跳转的资源间传递数据</strong>，此时处理器方法返回 ModelAndView 比较好。当然，若要返回 ModelAndView，则处理器方法中需要定义 ModelAndView 对象。</p>
<p>在使用时，若该处理器方法只是进行跳转而不传递数据，或只是传递数据而并不向任何资源跳转（如对页面的 Ajax 异步响应），此时若返回 ModelAndView，则将总是有一部分多余：要么 Model 多余，要么 View 多余。即此时返回 ModelAndView 将不合适。</p>
<h4 id="5-4-2-返回-String"><a href="#5-4-2-返回-String" class="headerlink" title="5.4.2 返回 String"></a>5.4.2 返回 String</h4><p>返回的字符串可以指定要转发的逻辑视图</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Controller</span><br><span class="hljs-meta">@RequestMapping(&quot;/test&quot;)</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyController</span> </span>&#123;<br><br>    <span class="hljs-meta">@RequestMapping(&quot;/test1&quot;)</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">test1</span><span class="hljs-params">()</span> </span>&#123;<br>        <span class="hljs-comment">// 直接返回逻辑视图的名称（因为在配置文件中已经配置好了视图解析器）</span><br>        <span class="hljs-keyword">return</span> <span class="hljs-string">&quot;show1&quot;</span>;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>直接返回逻辑视图名称前提是在 springmvc 配置文件中配置了视图解析器</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;org.springframework.web.servlet.view.InternalResourceViewResolver&quot;</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;prefix&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;/WEB-INF/view/&quot;</span>/&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;suffix&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;.jsp&quot;</span>/&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">bean</span>&gt;</span><br></code></pre></td></tr></table></figure>

<p>当然不指定视图解析器，方法中就要返回视图的路径了</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Controller</span><br><span class="hljs-meta">@RequestMapping(&quot;/test&quot;)</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyController</span> </span>&#123;<br><br>    <span class="hljs-meta">@RequestMapping(&quot;/test1&quot;)</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">test1</span><span class="hljs-params">()</span> </span>&#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-string">&quot;/WEB-INF/view/show1.jsp&quot;</span>;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>show1.jsp</p>
<figure class="highlight jsp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs jsp">&lt;%@ page contentType=<span class="hljs-string">&quot;text/html;charset=UTF-8&quot;</span> language=<span class="hljs-string">&quot;java&quot;</span> %&gt;<br>&lt;html&gt;<br>&lt;head&gt;<br>    &lt;title&gt;show1&lt;/title&gt;<br>&lt;/head&gt;<br>&lt;body&gt;<br>返回值为 String 的处理器方法跳转到 show1.jsp<br>&lt;/body&gt;<br>&lt;/html&gt;<br></code></pre></td></tr></table></figure>

<p>测试：</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210718/image.2gxh357andc0.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p>当然如果跳转的页面需要处理器方法传递值，可以在方法中使用 HttpServletRequest 对象，将数据保存在 request 域对象中</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@RequestMapping(&quot;/test2&quot;)</span><br><span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">test2</span><span class="hljs-params">(HttpServletRequest request, String name)</span> </span>&#123;<br>    <span class="hljs-comment">// 传递参数</span><br>    request.setAttribute(<span class="hljs-string">&quot;msg&quot;</span>, <span class="hljs-string">&quot;从前端传递过来的参数：&quot;</span>+name);<br>    <span class="hljs-keyword">return</span> <span class="hljs-string">&quot;show2&quot;</span>;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>show2.jsp</p>
<figure class="highlight jsp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs jsp">&lt;%@ page contentType=<span class="hljs-string">&quot;text/html;charset=UTF-8&quot;</span> language=<span class="hljs-string">&quot;java&quot;</span> %&gt;<br>&lt;html&gt;<br>&lt;head&gt;<br>    &lt;title&gt;show2&lt;/title&gt;<br>&lt;/head&gt;<br>&lt;body&gt;<br>&lt;h2&gt;$&#123;msg&#125;&lt;/h2&gt;<br>&lt;/body&gt;<br>&lt;/html&gt;<br></code></pre></td></tr></table></figure>

<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210718/image.1il5s5i6c6dc.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<h4 id="5-4-3-无返回值-void"><a href="#5-4-3-无返回值-void" class="headerlink" title="5.4.3 无返回值 void"></a>5.4.3 无返回值 void</h4><p>对于处理器方法返回 void 的应用场景，AJAX 响应.</p>
<p>若处理器对请求处理后，<strong>无需跳转到其它任何资源</strong>，此时可以让处理器方法返回 void。</p>
<p>使用 AJAX 异步请求：</p>
<p><strong>step0：导入 jackson 依赖，引入 jquery</strong> </p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>com.fasterxml.jackson.core<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>jackson-core<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>2.11.4<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br><br><span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>com.fasterxml.jackson.core<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>jackson-databind<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>2.11.4<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br></code></pre></td></tr></table></figure>

<p>引入 jquery</p>
<figure class="highlight jsp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs jsp">&lt;%-- 引入 jquery --%&gt;<br>&lt;script type=<span class="hljs-string">&quot;text/javascript&quot;</span> src=<span class="hljs-string">&quot;http://code.jquery.com/jquery-1.11.1.min.js&quot;</span>&gt;&lt;/script&gt;<br></code></pre></td></tr></table></figure>

<p><strong>step1：编写请求页面 index.jsp</strong></p>
<figure class="highlight jsp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><code class="hljs jsp">&lt;%@ page contentType=<span class="hljs-string">&quot;text/html; charset=UTF-8&quot;</span> pageEncoding=<span class="hljs-string">&quot;UTF-8&quot;</span> %&gt;<br>&lt;!DOCTYPE html&gt;<br>&lt;html&gt;<br>&lt;head&gt;<br>    &lt;title&gt;AJAX&lt;/title&gt;<br>    &lt;!-- 引入 jquery --&gt;<br>    &lt;script type=<span class="hljs-string">&quot;text/javascript&quot;</span> src=<span class="hljs-string">&quot;http://code.jquery.com/jquery-1.11.1.min.js&quot;</span>&gt;&lt;/script&gt;<br>    &lt;script type=<span class="hljs-string">&quot;text/javascript&quot;</span>&gt;<br>        $(function () &#123;<br>            $(<span class="hljs-string">&quot;#ajaxBtn&quot;</span>).click(function () &#123;<br>                $.ajax(&#123;<br>                    url : <span class="hljs-string">&quot;test/test3&quot;</span>,<br>                    data : &#123;<br>                        name : <span class="hljs-string">&quot;yechen&quot;</span>,<br>                        age : <span class="hljs-string">&quot;20&quot;</span><br>                    &#125;,<br>                    type : <span class="hljs-string">&quot;get&quot;</span>,<br>                    dataType : <span class="hljs-string">&quot;json&quot;</span>,<br>                    success : function (data) &#123;<br>                        alert(<span class="hljs-string">&quot;data = &#123;name = &quot;</span>+data.name+<span class="hljs-string">&quot;, age = &quot;</span>+data.age+<span class="hljs-string">&quot;&#125;&quot;</span>)<br>                    &#125;<br>                &#125;)<br>            &#125;)<br>        &#125;)<br>    &lt;/script&gt;<br>&lt;/head&gt;<br>&lt;body&gt;<br>    &lt;!-- 发送 AJAX 请求的按钮 --&gt;<br>    &lt;input type=<span class="hljs-string">&quot;button&quot;</span> value=<span class="hljs-string">&quot;发起ajax请求&quot;</span> id=<span class="hljs-string">&quot;ajaxBtn&quot;</span>&gt;<br>&lt;/body&gt;<br>&lt;/html&gt;<br></code></pre></td></tr></table></figure>

<p><strong>step2：编写处理器方法</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@RequestMapping(&quot;/test3&quot;)</span><br><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">test3</span><span class="hljs-params">(User user, HttpServletResponse response)</span> <span class="hljs-keyword">throws</span> IOException </span>&#123;<br>    <span class="hljs-comment">// 将获取的 User 对象转成 json 字符串</span><br>    ObjectMapper objectMapper = <span class="hljs-keyword">new</span> ObjectMapper();<br>    String json = objectMapper.writeValueAsString(user);<br><br>    <span class="hljs-comment">// 使用 response 输出数据到浏览器</span><br>    PrintWriter writer = response.getWriter();<br>    writer.println(json);<br>    writer.flush();<br>    writer.close();<br>&#125;<br></code></pre></td></tr></table></figure>

<p><strong>step3：运行测试</strong></p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210718/image.785m78x4w5s0.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<h4 id="5-4-4-返回对象-Object"><a href="#5-4-4-返回对象-Object" class="headerlink" title="5.4.4 返回对象 Object"></a>5.4.4 返回对象 Object</h4><p>处理器方法也可以返回 Object 对象。这个 Object 可以是 Integer，String，自定义对象，Map，List 等。但返回的对象不是作为逻辑视图出现的，而是作为直接在页面<strong>显示的数据出现</strong>的。</p>
<p>相当于将我们之间无返回的方法中的步骤全部省略，对象转为 json 字符串、使用 response 输出数据到浏览器这些都由框架内部完成了，我们只要返回处理好的对象就行。于是对于上一个例子，处理器方法就能简化为：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@RequestMapping(&quot;/test4&quot;)</span><br><span class="hljs-meta">@ResponseBody</span><br><span class="hljs-function"><span class="hljs-keyword">public</span> User <span class="hljs-title">test4</span><span class="hljs-params">(User user)</span> </span>&#123;<br>    <span class="hljs-keyword">return</span> user;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>将 Object 数据转化为 JSON 数据，需要由消息转换器 <code>HttpMessageConverter</code> 完成。而转换器的开启，需要由 <code>&lt;mvc:annotation-driven/&gt;</code>来完成。</p>
<p>而将 JSON 数据返回浏览器，需要使用 <code>@ResponseBody</code> 注解，将转换后的 JSON 数据放入到响应体中。</p>
<p><strong>内部原理</strong>：</p>
<p><code>&lt;mvc:annotation-driven/&gt;</code> 注解驱动实现的功能是：完成 Java 对象到 JSON、XML、text、二进制等数据格式的转换。具体功能是由 <code>HttpMessageConverter</code>（消息转换器）接口的具体实现类来处理数据的。</p>
<p><code>HttpMessageConverter</code> 中定义了 Java 对象转为 JSON、XML 等数据格式的方法，并且有许多实现类，分别完成不同的类型转换。</p>
<p>其中有方法就是用来判断 Java 对象是否可以装换成指定的数据，有方法用来完成数据转换</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-comment">// 指示此转换器是否可以写入给定的类。</span><br><span class="hljs-function"><span class="hljs-keyword">boolean</span> <span class="hljs-title">canWrite</span><span class="hljs-params">(Class&lt;?&gt; clazz, <span class="hljs-meta">@Nullable</span> MediaType mediaType)</span></span>;<br><br><span class="hljs-comment">// 将给定的对象写入给定的输出消息</span><br><span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">write</span><span class="hljs-params">(T t, <span class="hljs-meta">@Nullable</span> MediaType contentType, HttpOutputMessage outputMessage)</span></span><br><span class="hljs-function">			<span class="hljs-keyword">throws</span> IOException, HttpMessageNotWritableException</span>;<br></code></pre></td></tr></table></figure>

<p><code>&lt;mvc:annotation-driven/&gt;</code> 在配置文件中指定后，在容器初始化时，会自动创建八个 HttpMessageConverter 的实现，来实现不同数据的转换。具体八个实现类如下：</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210718/image.6rsb5ai47qo0.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210718/image.2t9xvqxti520.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p><code>MappingJackson2HttpMessageConverter</code> 类是我们经常使用到的，是使用了 Jackson 工具来将 Java 对象转换为 JSON 格式字符串的。</p>
<p><code>@ResponseBody</code> 注解放在处理器方法的上方，通过 HttpServletResponse 输出数据，响应 AJAX 请求，其取代的就是之间的响应数据部分</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-comment">// 使用 response 输出数据到浏览器</span><br>PrintWriter writer = response.getWriter();<br>writer.println(json);<br></code></pre></td></tr></table></figure>



<h5 id="例子一：返回自定义对象-User"><a href="#例子一：返回自定义对象-User" class="headerlink" title="例子一：返回自定义对象 User"></a><strong>例子一：返回自定义对象 User</strong></h5><p>请求页面 index3.jsp，没有请求参数</p>
<figure class="highlight jsp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><code class="hljs jsp">&lt;%@ page contentType=<span class="hljs-string">&quot;text/html; charset=UTF-8&quot;</span> pageEncoding=<span class="hljs-string">&quot;UTF-8&quot;</span> %&gt;<br>&lt;!DOCTYPE html&gt;<br>&lt;html&gt;<br>&lt;head&gt;<br>    &lt;title&gt;AJAX&lt;/title&gt;<br>    &lt;!-- 引入 jquery --&gt;<br>    &lt;script type=<span class="hljs-string">&quot;text/javascript&quot;</span> src=<span class="hljs-string">&quot;http://code.jquery.com/jquery-1.11.1.min.js&quot;</span>&gt;&lt;/script&gt;<br>    &lt;script type=<span class="hljs-string">&quot;text/javascript&quot;</span>&gt;<br>        $(function () &#123;<br>            $(<span class="hljs-string">&quot;#ajaxBtn&quot;</span>).click(function () &#123;<br>                $.ajax(&#123;<br>                    url : <span class="hljs-string">&quot;object/returnUser&quot;</span>,<br>                    type : <span class="hljs-string">&quot;get&quot;</span>,<br>                    dataType : <span class="hljs-string">&quot;json&quot;</span>,<br>                    success : function (data) &#123;<br>                        alert(<span class="hljs-string">&quot;name = &quot;</span>+data.name+<span class="hljs-string">&quot;, age = &quot;</span>+data.age+<span class="hljs-string">&quot;，email = &quot;</span>+data.email)<br>                    &#125;<br>                &#125;)<br>            &#125;)<br>        &#125;)<br>    &lt;/script&gt;<br>&lt;/head&gt;<br>&lt;body&gt;<br>    &lt;input type=<span class="hljs-string">&quot;button&quot;</span> value=<span class="hljs-string">&quot;index3.jsp 发起ajax请求 返回一个 User&quot;</span> id=<span class="hljs-string">&quot;ajaxBtn&quot;</span>&gt;<br>&lt;/body&gt;<br>&lt;/html&gt;<br></code></pre></td></tr></table></figure>

<p>springmvc 配置文件中加入注解驱动</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">mvc:annotation-driven</span>/&gt;</span><br></code></pre></td></tr></table></figure>

<p>注意这个注解驱动的限制文件是</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs xml">xmlns:mvc=&quot;http://www.springframework.org/schema/mvc&quot;<br>xsi:schemaLocation=&quot;http://www.springframework.org/schema/mvc<br>        https://www.springframework.org/schema/mvc/spring-mvc.xsd&quot;<br></code></pre></td></tr></table></figure>

<p>编写处理器方法 </p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Controller</span><br><span class="hljs-meta">@RequestMapping(&quot;/object&quot;)</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ObjectController</span> </span>&#123;<br><br>    <span class="hljs-comment">// 返回自定义的类 User</span><br>    <span class="hljs-meta">@RequestMapping(&quot;/returnUser&quot;)</span><br>    <span class="hljs-meta">@ResponseBody</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> User <span class="hljs-title">UserTest</span><span class="hljs-params">()</span> </span>&#123;<br>        User user = <span class="hljs-keyword">new</span> User();<br>        user.setName(<span class="hljs-string">&quot;zhangsan&quot;</span>);<br>        user.setAge(<span class="hljs-number">18</span>);<br>        user.setEmail(<span class="hljs-string">&quot;1234567@qq.com&quot;</span>);<br>        <span class="hljs-comment">// 返回后会被框架转换为 JSON 格式字符串</span><br>        <span class="hljs-keyword">return</span> user;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>测试结果</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210718/image.75wrzz03dek0.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p>执行流程：</p>
<ol>
<li>框架会把处理器方法返回的 user 对象作为参数，调用容器中生成的 HttpMessageConverter 接口实现类的 canWrite() 方法，由于这些实现类都保存在一个 <code>ArrayLis&lt;HttpMessageConverter&gt;</code> 集合中，因此编历集合即可找到能处理 user 类型数据的实现类，即 <code>MappingJackson2HttpMessageConverter</code></li>
<li>之后就会调用 <code>MappingJackson2HttpMessageConverter</code> 的 write() 方法，将 user 对象转换为 JSON 字符串，其中就用到了 Jackson 工具。</li>
<li>最后框架会根据注解 @ResponseBody，将 JSON 字符串输出到浏览器，AJAX 请求处理完成。</li>
</ol>
<h5 id="例子二：返回自定义对象列表-List-lt-User-gt"><a href="#例子二：返回自定义对象列表-List-lt-User-gt" class="headerlink" title="例子二：返回自定义对象列表 List&lt;User&gt;"></a><strong>例子二：返回自定义对象列表 List&lt;User&gt;</strong></h5><p>请求页面 index4.jsp</p>
<figure class="highlight jsp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><code class="hljs jsp">&lt;%@ page contentType=<span class="hljs-string">&quot;text/html; charset=UTF-8&quot;</span> pageEncoding=<span class="hljs-string">&quot;UTF-8&quot;</span> %&gt;<br>&lt;!DOCTYPE html&gt;<br>&lt;html&gt;<br>&lt;head&gt;<br>    &lt;title&gt;AJAX&lt;/title&gt;<br>    &lt;!-- 引入 jquery --&gt;<br>    &lt;script type=<span class="hljs-string">&quot;text/javascript&quot;</span> src=<span class="hljs-string">&quot;http://code.jquery.com/jquery-1.11.1.min.js&quot;</span>&gt;&lt;/script&gt;<br>    &lt;script type=<span class="hljs-string">&quot;text/javascript&quot;</span>&gt;<br>        $(function () &#123;<br>            $(<span class="hljs-string">&quot;#ajaxBtn&quot;</span>).click(function () &#123;<br>                $.ajax(&#123;<br>                    url : <span class="hljs-string">&quot;object/returnList&quot;</span>,<br>                    type : <span class="hljs-string">&quot;get&quot;</span>,<br>                    dataType : <span class="hljs-string">&quot;json&quot;</span>,<br>                    success : function (data) &#123;<br>                        <span class="hljs-keyword">var</span> msg = <span class="hljs-string">&quot;&quot;</span>;<br>                        <span class="hljs-comment">// 编历 json 数组</span><br>                        $.each(data, function (index, element) &#123;<br>                            msg += <span class="hljs-string">&quot;name = &quot;</span>+element.name+<span class="hljs-string">&quot;, age = &quot;</span>+element.age+<span class="hljs-string">&quot;，email = &quot;</span>+element.email+<span class="hljs-string">&quot;\n&quot;</span>;<br>                        &#125;)<br>                        alert(msg);<br>                    &#125;<br>                &#125;)<br>            &#125;)<br>        &#125;)<br>    &lt;/script&gt;<br>&lt;/head&gt;<br>&lt;body&gt;<br>    &lt;input type=<span class="hljs-string">&quot;button&quot;</span> value=<span class="hljs-string">&quot;index4.jsp 发起ajax请求 返回一个 UserList&quot;</span> id=<span class="hljs-string">&quot;ajaxBtn&quot;</span>&gt;<br>&lt;/body&gt;<br>&lt;/html&gt;<br></code></pre></td></tr></table></figure>

<p>编写处理器方法 </p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Controller</span><br><span class="hljs-meta">@RequestMapping(&quot;/object&quot;)</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ObjectController</span> </span>&#123;<br>    <span class="hljs-comment">// 返回 User 列表</span><br>    <span class="hljs-meta">@RequestMapping(&quot;/returnList&quot;)</span><br>    <span class="hljs-meta">@ResponseBody</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> List&lt;User&gt; <span class="hljs-title">ListTest</span><span class="hljs-params">()</span> </span>&#123;<br>        List&lt;User&gt; userList = <span class="hljs-keyword">new</span> ArrayList&lt;&gt;();<br><br>        User user = <span class="hljs-keyword">new</span> User();<br>        user.setName(<span class="hljs-string">&quot;张三&quot;</span>);<br>        user.setAge(<span class="hljs-number">18</span>);<br>        user.setEmail(<span class="hljs-string">&quot;1234567@qq.com&quot;</span>);<br><br>        User user1 = <span class="hljs-keyword">new</span> User();<br>        user1.setName(<span class="hljs-string">&quot;李四&quot;</span>);<br>        user1.setAge(<span class="hljs-number">20</span>);<br>        user1.setEmail(<span class="hljs-string">&quot;987654321@qq.com&quot;</span>);<br><br>        userList.add(user);<br>        userList.add(user1);<br>        <span class="hljs-comment">// 返回后会被框架转换为 JSON 格式的数组</span><br>        <span class="hljs-keyword">return</span> userList;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>测试结果：</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210719/image.5t5j0kqmli8.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<h5 id="例子三：返回文本-String"><a href="#例子三：返回文本-String" class="headerlink" title="例子三：返回文本 String"></a><strong>例子三：返回文本 String</strong></h5><p>这里返回的 String 表示的数据，不是视图。</p>
<p>区分返回值是数据还是视图，就看处理器方法上有没有 @ResponseBody 注解，如果有 @ResponseBody  注解，返回值就是数据，反之就是视图。</p>
<p>请求页面 index5.jsp</p>
<figure class="highlight jsp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><code class="hljs jsp">&lt;%@ page contentType=<span class="hljs-string">&quot;text/html; charset=UTF-8&quot;</span> pageEncoding=<span class="hljs-string">&quot;UTF-8&quot;</span> %&gt;<br>&lt;!DOCTYPE html&gt;<br>&lt;html&gt;<br>&lt;head&gt;<br>    &lt;title&gt;AJAX&lt;/title&gt;<br>    &lt;%-- 引入 jquery --%&gt;<br>    &lt;script type=<span class="hljs-string">&quot;text/javascript&quot;</span> src=<span class="hljs-string">&quot;http://code.jquery.com/jquery-1.11.1.min.js&quot;</span>&gt;&lt;/script&gt;<br>    &lt;script type=<span class="hljs-string">&quot;text/javascript&quot;</span>&gt;<br>        $(function () &#123;<br>            <span class="hljs-comment">// 由于返回的是文本数据，所以这里 dataType 就不能写 json，因为后端不能把 String 类型数据转换为 json 字符串</span><br>            <span class="hljs-comment">// 所有这里可以不写 dataType 或者将 dataType 设置为 text</span><br>            $(<span class="hljs-string">&quot;#ajaxBtn&quot;</span>).click(function () &#123;<br>                $.ajax(&#123;<br>                    url : <span class="hljs-string">&quot;object/returnString&quot;</span>,<br>                    type : <span class="hljs-string">&quot;get&quot;</span>,<br>                    success : function (data) &#123;<br>                        alert(<span class="hljs-string">&quot;返回的是文本数据：&quot;</span>+data);<br>                    &#125;<br>                &#125;)<br>            &#125;)<br>        &#125;)<br>    &lt;/script&gt;<br>&lt;/head&gt;<br>&lt;body&gt;<br>    &lt;input type=<span class="hljs-string">&quot;button&quot;</span> value=<span class="hljs-string">&quot;index5.jsp 发起ajax请求 返回一个 String 文本&quot;</span> id=<span class="hljs-string">&quot;ajaxBtn&quot;</span>&gt;<br>&lt;/body&gt;<br>&lt;/html&gt;<br></code></pre></td></tr></table></figure>

<p>处理器方法 </p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Controller</span><br><span class="hljs-meta">@RequestMapping(&quot;/object&quot;)</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ObjectController</span> </span>&#123;<br><br>    <span class="hljs-comment">// 返回 String 字符串，是数据，不是视图</span><br>    <span class="hljs-meta">@RequestMapping(&quot;/returnString&quot;)</span><br>    <span class="hljs-meta">@ResponseBody</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">StringTest</span><span class="hljs-params">()</span> </span>&#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-string">&quot;Hello SpringMVC，返回对象 String，表示数据&quot;</span>;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>测试结果：</p>
<p><img src="../../../AppData/Roaming/Typora/typora-user-images/image-20210719115203671.png" srcset="/img/loading.gif" lazyload alt="image-20210719115203671"></p>
<p>这里为什么会出现中文乱码呢？是因为服务器响应文本默认的编码格式是 ISO-8859-1，不支持中文编码。</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210719/image.52eofvqhjp80.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p>那么怎么解决呢？我们可以自己在 @RequestMapping 注解中增加一个属性 <code>produces</code>，使用这个属性就可以指定新的 contextType</p>
<p>修改控制器方法</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Controller</span><br><span class="hljs-meta">@RequestMapping(&quot;/object&quot;)</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ObjectController</span> </span>&#123;<br><br>    <span class="hljs-meta">@RequestMapping(value = &quot;/returnString&quot;, produces = &quot;text/plain;charset=UTF-8&quot;)</span><br>    <span class="hljs-meta">@ResponseBody</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">StringTest</span><span class="hljs-params">()</span> </span>&#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-string">&quot;Hello SpringMVC，返回对象 String，表示数据&quot;</span>;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>测试结果：</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210719/image.6m0cqcgxg0k0.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p>此时响应编码是</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210719/image.3hgk5m7clv20.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p><img src="../../../AppData/Roaming/Typora/typora-user-images/image-20210719121021800.png" srcset="/img/loading.gif" lazyload alt="image-20210719121021800"></p>
<p>执行流程：</p>
<ol>
<li>框架会把处理器方法返回的 String 作为参数，调用容器中生成的 HttpMessageConverter 接口实现类的 canWrite() 方法，由于这些实现类都保存在一个 <code>ArrayLis&lt;HttpMessageConverter&gt;</code> 集合中，因此编历集合即可找到能处理 String 类型数据的实现类，即 <code>StringHttpMessageConverter</code></li>
<li>之后就会调用 <code>StringHttpMessageConverter</code> 的 write() 方法，按照默认（或自己指定）的编码方式处理数据。</li>
<li>最后框架会根据注解 @ResponseBody，将处理好的数据返回给浏览器，AJAX 请求处理完成。</li>
</ol>
<h3 id="5-5-详细了解-url-pattern"><a href="#5-5-详细了解-url-pattern" class="headerlink" title="5.5 详细了解 url-pattern"></a>5.5 详细了解 url-pattern</h3><h4 id="5-5-1-Tomcat-中的-Servlet"><a href="#5-5-1-Tomcat-中的-Servlet" class="headerlink" title="5.5.1 Tomcat 中的 Servlet"></a>5.5.1 Tomcat 中的 Servlet</h4><p>在Tomcat 安装目录下的 conf 目录下存在一个 web.xml 文件，在其中注册了两个 Servlet，是 Tomcat 用来处理静态文件和 jsp 文件的，直接上源代码</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-comment">&lt;!-- 处理所有静态文件的 servlet --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">servlet</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">servlet-name</span>&gt;</span>default<span class="hljs-tag">&lt;/<span class="hljs-name">servlet-name</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">servlet-class</span>&gt;</span>org.apache.catalina.servlets.DefaultServlet<span class="hljs-tag">&lt;/<span class="hljs-name">servlet-class</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">init-param</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">param-name</span>&gt;</span>debug<span class="hljs-tag">&lt;/<span class="hljs-name">param-name</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">param-value</span>&gt;</span>0<span class="hljs-tag">&lt;/<span class="hljs-name">param-value</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">init-param</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">init-param</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">param-name</span>&gt;</span>listings<span class="hljs-tag">&lt;/<span class="hljs-name">param-name</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">param-value</span>&gt;</span>false<span class="hljs-tag">&lt;/<span class="hljs-name">param-value</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">init-param</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">load-on-startup</span>&gt;</span>1<span class="hljs-tag">&lt;/<span class="hljs-name">load-on-startup</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">servlet</span>&gt;</span><br><span class="hljs-comment">&lt;!-- The mapping for the default servlet --&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">servlet-mapping</span>&gt;</span><br>     <span class="hljs-tag">&lt;<span class="hljs-name">servlet-name</span>&gt;</span>default<span class="hljs-tag">&lt;/<span class="hljs-name">servlet-name</span>&gt;</span><br>     <span class="hljs-tag">&lt;<span class="hljs-name">url-pattern</span>&gt;</span>/<span class="hljs-tag">&lt;/<span class="hljs-name">url-pattern</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">servlet-mapping</span>&gt;</span><br><br><span class="hljs-tag">&lt;<span class="hljs-name">servlet</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">servlet-name</span>&gt;</span>jsp<span class="hljs-tag">&lt;/<span class="hljs-name">servlet-name</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">servlet-class</span>&gt;</span>org.apache.jasper.servlet.JspServlet<span class="hljs-tag">&lt;/<span class="hljs-name">servlet-class</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">init-param</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">param-name</span>&gt;</span>fork<span class="hljs-tag">&lt;/<span class="hljs-name">param-name</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">param-value</span>&gt;</span>false<span class="hljs-tag">&lt;/<span class="hljs-name">param-value</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">init-param</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">init-param</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">param-name</span>&gt;</span>xpoweredBy<span class="hljs-tag">&lt;/<span class="hljs-name">param-name</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">param-value</span>&gt;</span>false<span class="hljs-tag">&lt;/<span class="hljs-name">param-value</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">init-param</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">load-on-startup</span>&gt;</span>3<span class="hljs-tag">&lt;/<span class="hljs-name">load-on-startup</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">servlet</span>&gt;</span><br><span class="hljs-comment">&lt;!-- The mappings for the JSP servlet --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">servlet-mapping</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">servlet-name</span>&gt;</span>jsp<span class="hljs-tag">&lt;/<span class="hljs-name">servlet-name</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">url-pattern</span>&gt;</span>*.jsp<span class="hljs-tag">&lt;/<span class="hljs-name">url-pattern</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">url-pattern</span>&gt;</span>*.jspx<span class="hljs-tag">&lt;/<span class="hljs-name">url-pattern</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">servlet-mapping</span>&gt;</span><br></code></pre></td></tr></table></figure>

<p>对 DefaultServlet 的描述：<strong>服务静态资源和未映射的其他 Servlet 的请求</strong></p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210719/image.4utmz5lq4uw0.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p>对 JspServlet 的描述：<strong>处理 jsp 文件的请求</strong></p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210719/image.4mly8a1xthc0.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<h4 id="5-5-2-servlet-容器对-url-的匹配过程"><a href="#5-5-2-servlet-容器对-url-的匹配过程" class="headerlink" title="5.5.2 servlet 容器对 url 的匹配过程"></a>5.5.2 servlet 容器对 url 的匹配过程</h4><p>当一个请求发送到 servlet 容器的时候，容器先会将请求的 url 减去当前应用上下文的路径作为 servlet 的映射 url，比如我访问的是 <a target="_blank" rel="noopener" href="http://localhost/test/aaa.html%EF%BC%8C%E6%88%91%E7%9A%84%E5%BA%94%E7%94%A8%E4%B8%8A%E4%B8%8B%E6%96%87%E6%98%AF">http://localhost/test/aaa.html，我的应用上下文是</a> test，容器会将 <a target="_blank" rel="noopener" href="http://localhost/test">http://localhost/test</a> 去掉， 剩下的 /aaa.html 部分拿来做 servlet 的映射匹配。这个映射匹配过程是有顺序的，而且当有一个 servlet 匹配成功以后，就不会去理会剩下的servlet了。其匹配规则和顺序如下：</p>
<ol>
<li><pre><code>**精确路径匹配**。例子：比如 servletA 的 url-pattern为 /test，servletB 的 url-pattern为 /* ，这个时候，如果我访问的url为 http://localhost/test ，这个时候容器就会先进行精确路径匹配，发现 /test 正好被 servletA 精确匹配，那么就去调用 servletA，也不会去理会其他的 servlet了。
</code></pre>
</li>
<li><pre><code>**最长路径匹配**。例子：servletA 的 url-pattern 为 /test/\*，而 servletB 的 url-pattern 为/test/a/*，此时访问 http://localhost/test/a 时，容器会选择路径最长的 servlet 来匹配，也就是这里的servletB。
</code></pre>
</li>
<li><pre><code>**扩展匹配**。如果 url 最后一段包含扩展，容器将会根据扩展选择合适的 servlet。例子：servletA 的 url-pattern：*.action
</code></pre>
</li>
<li><pre><code>如果前面三条规则都没有找到一个 servlet，容器会根据 url 选择对应的请求资源。容器会将请求丢给defaultServlet（什么是defaultServlet？后面会讲）。
</code></pre>
</li>
</ol>
<p>根据这个规则表，就能很清楚的知道servlet的匹配过程，所以定义servlet的时候也要考虑url-pattern的写法，以免出错。</p>
<p><strong>举个例子：</strong></p>
<ul>
<li>当 &lt;url-pattern&gt;/*&lt;/url-pattern&gt; 时，指定的 Servlet 会拦截所有请求包括静态资源请求、动态资源请求和 jsp 文件请求。能处理就处理，不能处理就报错。</li>
<li>当 &lt;url-pattern&gt;/&lt;/url-pattern&gt; 时，指定的 Servlet 会拦截除 .jsp 结尾的请求，其他包括静态资源和动态资源的请求，都会交给当前指定的 Servlet 来处理。而 .jsp 结尾的请求就会由 Tomcat 中的 JspServlet 来处理。</li>
<li>当 &lt;url-pattern&gt;*.do&lt;/url-pattern&gt;时，指定当前 Servlet 只会处理以 .do 结尾的动态资源请求，静态资源会由 Tomcat 中的 DefaultServlet 来处理，.jsp 结尾的请求就会由 Tomcat 中的 JspServlet 来处理。</li>
</ul>
<blockquote>
<p>总结：在 servlet 容器对 url 的匹配过程中，会优先根据当前项目中 web.xml 文件中指定的 Servlet 的 url-pattern 来匹配路径，如果路径匹配上了，当前 Servlet 就会拦截该请求并处理，若是没有匹配到，就由Tomat 中的两个 Servlet 来分别处理静态资源和 jsp 文件。</p>
</blockquote>
<h4 id="5-5-3-测试-访问静态资源"><a href="#5-5-3-测试-访问静态资源" class="headerlink" title="5.5.3 测试 / 访问静态资源"></a>5.5.3 测试 / 访问静态资源</h4><p>我们之前在 web.xml 文件中注册 DispatcherServlet 指定的 url-pattern 是 “/“，由于访问的都是动态资源和 jsp 页面，所以没有出现资源不能访问的情况，但是当我们要访问静态资源的时候，就会出现问题。</p>
<p><strong>先准备一下环境：</strong></p>
<p>先在项目中加入一些静态资源（html，js，css，image 等）</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210719/image.1poru0wo7zgg.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p>编写请求页面 index.jsp</p>
<figure class="highlight jsp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><code class="hljs jsp">&lt;%@ page contentType=<span class="hljs-string">&quot;text/html;charset=UTF-8&quot;</span> language=<span class="hljs-string">&quot;java&quot;</span> %&gt;<br>&lt;html&gt;<br>&lt;head&gt;<br>    &lt;title&gt;测试 url-pattern&lt;/title&gt;<br>    &lt;!-- 在这里会引入静态资源 --&gt;<br>    &lt;script type=<span class="hljs-string">&quot;text/javascript&quot;</span> src=<span class="hljs-string">&quot;js/jquery-1.11.1-min.js&quot;</span>&gt;&lt;/script&gt;<br>&lt;/head&gt;<br>&lt;body&gt;<br>&lt;!-- 这里会访问动态资源 --&gt;<br>&lt;form action=<span class="hljs-string">&quot;test/first.do&quot;</span> method=<span class="hljs-string">&quot;post&quot;</span>&gt;<br>    &lt;table&gt;<br>        &lt;tr&gt;<br>            &lt;td&gt;姓名&lt;/td&gt;<br>            &lt;td&gt; &lt;input type=<span class="hljs-string">&quot;text&quot;</span> name=<span class="hljs-string">&quot;name&quot;</span>&gt;&lt;/td&gt;<br>        &lt;/tr&gt;<br>        &lt;tr&gt;<br>            &lt;td&gt; 年龄&lt;/td&gt;<br>            &lt;td&gt;&lt;input type=<span class="hljs-string">&quot;text&quot;</span> name=<span class="hljs-string">&quot;age&quot;</span>&gt;&lt;/td&gt;<br>        &lt;/tr&gt;<br>        &lt;tr&gt;<br>            &lt;td&gt;&lt;/td&gt;<br>            &lt;td&gt;&lt;input type=<span class="hljs-string">&quot;submit&quot;</span> value=<span class="hljs-string">&quot;提交&quot;</span>&gt;&lt;/td&gt;<br>        &lt;/tr&gt;<br>    &lt;/table&gt;<br>&lt;/form&gt;<br>&lt;br/&gt;<br>&lt;!-- 在这里会引入静态资源 --&gt;<br>&lt;img src=<span class="hljs-string">&quot;images/1.jpg&quot;</span> alt=<span class="hljs-string">&quot;第一张图片&quot;</span>&gt;<br>&lt;/body&gt;<br>&lt;/html&gt;<br></code></pre></td></tr></table></figure>

<p>编写一个处理器方法，处理动态请求</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Controller</span><br><span class="hljs-meta">@RequestMapping(&quot;/test&quot;)</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyController</span> </span>&#123;<br><br><br>    <span class="hljs-meta">@RequestMapping(&quot;/first.do&quot;)</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> ModelAndView <span class="hljs-title">first</span><span class="hljs-params">(String name, Integer age)</span> </span>&#123;<br>        ModelAndView modelAndView = <span class="hljs-keyword">new</span> ModelAndView();<br>        String msg = <span class="hljs-string">&quot;name = &quot;</span> + name + <span class="hljs-string">&quot;，age = &quot;</span> + age;<br>        modelAndView.addObject(<span class="hljs-string">&quot;msg&quot;</span>,  msg);<br>        modelAndView.setViewName(<span class="hljs-string">&quot;show&quot;</span>);<br>        <span class="hljs-keyword">return</span> modelAndView;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>动态请求结果展示页面</p>
<figure class="highlight jsp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs jsp">&lt;%@ page contentType=<span class="hljs-string">&quot;text/html;charset=UTF-8&quot;</span> language=<span class="hljs-string">&quot;java&quot;</span> %&gt;<br>&lt;html&gt;<br>&lt;head&gt;<br>    &lt;title&gt;展示数据&lt;/title&gt;<br>&lt;/head&gt;<br>&lt;body&gt;<br>&lt;h3&gt;$&#123;msg&#125;&lt;/h3&gt;<br>&lt;/body&gt;<br>&lt;/html&gt;<br></code></pre></td></tr></table></figure>

<p>此时 url-pattern 设置为</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">url-pattern</span>&gt;</span>/<span class="hljs-tag">&lt;/<span class="hljs-name">url-pattern</span>&gt;</span><br></code></pre></td></tr></table></figure>

<p>访问 index.jsp，<strong>可以观察到 jsp 页面是成功访问了的</strong></p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210719/image.451pon9u18g0.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p>可以观察到静态资源没有被引进来</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210719/image.5ayrtjaq4r00.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p>再点击提交按钮，提交表单，访问动态资源</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210719/image.dsyp57b6vsw.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<blockquote>
<p>原因也是非常好理解的，由于指定了 <code>&lt;url-pattern&gt;/&lt;/url-pattern&gt;</code>，所以 DispatcherServlet 会拦截所有动态和静态资源的请求，对于动态资源，DispatcherServlet 可以处理，因为我们已经写好了对应路径的处理器方法；但是对于静态资源，DispatcherServlet 默认是没有处理静态资源的能力的，同时又不能将请求再交给 DefaultServlet  来完成，所以静态资源不能访问到。</p>
</blockquote>
<h4 id="5-5-3-静态资源访问"><a href="#5-5-3-静态资源访问" class="headerlink" title="5.5.3 静态资源访问"></a>5.5.3 静态资源访问</h4><p>&lt;url-pattern&gt; 的值并不是说写为 “/“ 后，静态资源就无法访问了。经过一些配置后，该问题也是可以解决的。</p>
<p><strong>（1）使用 &lt;mvc:default-servlet-handler/&gt;</strong></p>
<p>声明了 &lt;mvc:default-servlet-handler /&gt; 后 ， springmvc 框架会在容器中创建 <code>DefaultServletHttpRequestHandler</code> 处理器对象。<strong>它会像一个检查员，对进入 DispatcherServlet 的 URL 进行筛查，如果发现是静态资源的请求，就将该请求转由 Web 应用服务器默认的 Servlet 处理</strong>。Tomcat 中的默认 Servlet 就是之前提到的 DefaultServlet 啦。</p>
<p>&lt;mvc:default-servlet-handler/&gt; 表示使用 DefaultServletHttpRequestHandler 处理器对象。而该处理器调用 Tomcat 的 DefaultServlet 来处理静态资源的访问请求。</p>
<p>springmvc 配置文件</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-meta">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">beans</span> <span class="hljs-attr">xmlns</span>=<span class="hljs-string">&quot;http://www.springframework.org/schema/beans&quot;</span></span><br><span class="hljs-tag">       <span class="hljs-attr">xmlns:xsi</span>=<span class="hljs-string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span><br><span class="hljs-tag">       <span class="hljs-attr">xmlns:context</span>=<span class="hljs-string">&quot;http://www.springframework.org/schema/context&quot;</span></span><br><span class="hljs-tag">       <span class="hljs-attr">xmlns:mvc</span>=<span class="hljs-string">&quot;http://www.springframework.org/schema/mvc&quot;</span></span><br><span class="hljs-tag">       <span class="hljs-attr">xsi:schemaLocation</span>=<span class="hljs-string">&quot;http://www.springframework.org/schema/beans</span></span><br><span class="hljs-string"><span class="hljs-tag">        https://www.springframework.org/schema/beans/spring-beans.xsd</span></span><br><span class="hljs-string"><span class="hljs-tag">        http://www.springframework.org/schema/context</span></span><br><span class="hljs-string"><span class="hljs-tag">        https://www.springframework.org/schema/context/spring-context.xsd</span></span><br><span class="hljs-string"><span class="hljs-tag">        http://www.springframework.org/schema/mvc</span></span><br><span class="hljs-string"><span class="hljs-tag">        https://www.springframework.org/schema/mvc/spring-mvc.xsd&quot;</span>&gt;</span><br><br>    <span class="hljs-tag">&lt;<span class="hljs-name">context:component-scan</span> <span class="hljs-attr">base-package</span>=<span class="hljs-string">&quot;cn.yechen.controller&quot;</span>/&gt;</span><br><br>    <span class="hljs-tag">&lt;<span class="hljs-name">mvc:annotation-driven</span>/&gt;</span><br>    <br>    <span class="hljs-tag">&lt;<span class="hljs-name">mvc:default-servlet-handler</span>/&gt;</span><br><br>    <span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;org.springframework.web.servlet.view.InternalResourceViewResolver&quot;</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;prefix&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;/WEB-INF/view/&quot;</span>/&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;suffix&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;.jsp&quot;</span>/&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">bean</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">beans</span>&gt;</span><br></code></pre></td></tr></table></figure>

<p>此时 url-pattern</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">url-pattern</span>&gt;</span>/<span class="hljs-tag">&lt;/<span class="hljs-name">url-pattern</span>&gt;</span><br></code></pre></td></tr></table></figure>

<p>测试访问 index.jsp，图片进来了</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210719/image.wbyivliw6kg.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p>其他静态资源也进来了</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210719/image.488ot8laulw.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p>再点击提交按钮，提交表单，访问动态资源，也成功了</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210719/image.5pjl3d9rpvo0.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p><strong>（2）使用 &lt;mvc:resources/&gt;</strong></p>
<p>在 Spring3.0 版本后，Spring 定义了专门用于处理静态资源访问请求的处理器 <code>ResourceHttpRequestHandler</code>。并且添加了<code>&lt;mvc:resources/&gt;</code>标签，<strong>专门用于解决静态资源无法访问问题，不再依赖 Tomcat 服务器</strong>。</p>
<p>&lt;mvc:resources/&gt; 中有两个属性：</p>
<ol>
<li>mapping：访问静态资源的 URI 地址，使用通配符 ** 表示多级目录</li>
<li>location：静态资源在项目中的位置</li>
</ol>
<p>根据上面例子，我要访问 image、html、js 目录下是静态资源，在配置文件中就可以这样写</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">mvc:resources</span> <span class="hljs-attr">mapping</span>=<span class="hljs-string">&quot;/images/**&quot;</span> <span class="hljs-attr">location</span>=<span class="hljs-string">&quot;/images/&quot;</span>/&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">mvc:resources</span> <span class="hljs-attr">mapping</span>=<span class="hljs-string">&quot;/html/**&quot;</span> <span class="hljs-attr">location</span>=<span class="hljs-string">&quot;/html/&quot;</span>/&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">mvc:resources</span> <span class="hljs-attr">mapping</span>=<span class="hljs-string">&quot;/js/**&quot;</span> <span class="hljs-attr">location</span>=<span class="hljs-string">&quot;/js/&quot;</span>/&gt;</span><br></code></pre></td></tr></table></figure>

<p>静态资源都加载了</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210719/image.43j9gochs4u0.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210719/image.18txtlroi3nk.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p>为了简化配置，可以将静态资源都放在一个目录下，这样只要配置一个 &lt;mvc:resources/&gt; 了</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210719/image.6i41j0um0080.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p>配置：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">mvc:resources</span> <span class="hljs-attr">mapping</span>=<span class="hljs-string">&quot;/static/**&quot;</span> <span class="hljs-attr">location</span>=<span class="hljs-string">&quot;/static/&quot;</span>/&gt;</span><br></code></pre></td></tr></table></figure>



<h2 id="6-请求转发与重定向"><a href="#6-请求转发与重定向" class="headerlink" title="6. 请求转发与重定向"></a>6. 请求转发与重定向</h2><p>当处理器对请求处理完毕后，向其它资源进行跳转时，有两种跳转方式：<strong>请求转发与重定向</strong>。</p>
<p>而根据所要跳转的资源类型，又可分为两类：跳转到页面与跳转到其它处理器。</p>
<p>注意，对于请求转发的页面，可以是 WEB-INF 中页面；而重定向的页面，是不能为 WEB-INF 中的页面的，因为重定向相当于用户再次发出一次请求，而<strong>用户是不能直接访问 WEB-INF 中资源</strong>的。</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210721/image.5kv43rusa9c0.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p>SpringMVC 框架把原来 Servlet 中的请求转发和重定向操作进行了封装。现在可以使用简单的方式实现转发和重定向。</p>
<p><strong>环境准备：</strong></p>
<p>springmvc 配置</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-comment">&lt;!-- 组件扫描 --&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">context:component-scan</span> <span class="hljs-attr">base-package</span>=<span class="hljs-string">&quot;cn.yechen.controller&quot;</span>/&gt;</span><br>    <br><span class="hljs-comment">&lt;!-- 视图解析器，指定视图位置和扩展名 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;org.springframework.web.servlet.view.InternalResourceViewResolver&quot;</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;prefix&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;/WEB-INF/view/&quot;</span>/&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;suffix&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;.jsp&quot;</span>/&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">bean</span>&gt;</span><br></code></pre></td></tr></table></figure>

<p>web.xml </p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-meta">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">web-app</span> <span class="hljs-attr">xmlns</span>=<span class="hljs-string">&quot;http://xmlns.jcp.org/xml/ns/javaee&quot;</span></span><br><span class="hljs-tag">         <span class="hljs-attr">xmlns:xsi</span>=<span class="hljs-string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span><br><span class="hljs-tag">         <span class="hljs-attr">xsi:schemaLocation</span>=<span class="hljs-string">&quot;http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd&quot;</span></span><br><span class="hljs-tag">         <span class="hljs-attr">version</span>=<span class="hljs-string">&quot;4.0&quot;</span>&gt;</span><br><br>    <span class="hljs-comment">&lt;!-- 注册 DispatcherServlet --&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">servlet</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">servlet-name</span>&gt;</span>springmvc<span class="hljs-tag">&lt;/<span class="hljs-name">servlet-name</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">servlet-class</span>&gt;</span>org.springframework.web.servlet.DispatcherServlet<span class="hljs-tag">&lt;/<span class="hljs-name">servlet-class</span>&gt;</span><br><br>        <span class="hljs-tag">&lt;<span class="hljs-name">init-param</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">param-name</span>&gt;</span>contextConfigLocation<span class="hljs-tag">&lt;/<span class="hljs-name">param-name</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">param-value</span>&gt;</span>classpath:springmvc-servlet.xml<span class="hljs-tag">&lt;/<span class="hljs-name">param-value</span>&gt;</span><br>        <span class="hljs-tag">&lt;/<span class="hljs-name">init-param</span>&gt;</span><br><br>        <span class="hljs-tag">&lt;<span class="hljs-name">load-on-startup</span>&gt;</span>1<span class="hljs-tag">&lt;/<span class="hljs-name">load-on-startup</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">servlet</span>&gt;</span><br>    <span class="hljs-comment">&lt;!-- 拦截动态资源和静态资源 --&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">servlet-mapping</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">servlet-name</span>&gt;</span>springmvc<span class="hljs-tag">&lt;/<span class="hljs-name">servlet-name</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">url-pattern</span>&gt;</span>/<span class="hljs-tag">&lt;/<span class="hljs-name">url-pattern</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">servlet-mapping</span>&gt;</span><br><br>    <span class="hljs-comment">&lt;!-- 配置 SpringMVC 中自带的乱码过滤器 --&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">filter</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">filter-name</span>&gt;</span>encoding<span class="hljs-tag">&lt;/<span class="hljs-name">filter-name</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">filter-class</span>&gt;</span>org.springframework.web.filter.CharacterEncodingFilter<span class="hljs-tag">&lt;/<span class="hljs-name">filter-class</span>&gt;</span><br>        <span class="hljs-comment">&lt;!-- 设置项目使用的字符编码 --&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">init-param</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">param-name</span>&gt;</span>encoding<span class="hljs-tag">&lt;/<span class="hljs-name">param-name</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">param-value</span>&gt;</span>utf-8<span class="hljs-tag">&lt;/<span class="hljs-name">param-value</span>&gt;</span><br>        <span class="hljs-tag">&lt;/<span class="hljs-name">init-param</span>&gt;</span><br>        <span class="hljs-comment">&lt;!-- 强制请求对象（HttpServletRequest）使用 encoding 编码的值 --&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">init-param</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">param-name</span>&gt;</span>forceRequestEncoding<span class="hljs-tag">&lt;/<span class="hljs-name">param-name</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">param-value</span>&gt;</span>true<span class="hljs-tag">&lt;/<span class="hljs-name">param-value</span>&gt;</span><br>        <span class="hljs-tag">&lt;/<span class="hljs-name">init-param</span>&gt;</span><br>        <span class="hljs-comment">&lt;!-- 强制响应对象（HttpServletResponse）使用 encoding 编码的值 --&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">init-param</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">param-name</span>&gt;</span>forceResponseEncoding<span class="hljs-tag">&lt;/<span class="hljs-name">param-name</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">param-value</span>&gt;</span>true<span class="hljs-tag">&lt;/<span class="hljs-name">param-value</span>&gt;</span><br>        <span class="hljs-tag">&lt;/<span class="hljs-name">init-param</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">filter</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">filter-mapping</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">filter-name</span>&gt;</span>encoding<span class="hljs-tag">&lt;/<span class="hljs-name">filter-name</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">url-pattern</span>&gt;</span>/*<span class="hljs-tag">&lt;/<span class="hljs-name">url-pattern</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">filter-mapping</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">web-app</span>&gt;</span><br></code></pre></td></tr></table></figure>

<p>发起请求的页面 index.jsp</p>
<figure class="highlight jsp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><code class="hljs jsp">&lt;%@ page contentType=<span class="hljs-string">&quot;text/html;charset=UTF-8&quot;</span> language=<span class="hljs-string">&quot;java&quot;</span> %&gt;<br>&lt;%<br>    String basePath = request.getScheme() + <span class="hljs-string">&quot;://&quot;</span> + request.getServerName() + <span class="hljs-string">&quot;:&quot;</span> +    request.getServerPort() + request.getContextPath() + <span class="hljs-string">&quot;/&quot;</span>;<br>%&gt;<br>&lt;html&gt;<br>&lt;head&gt;<br>    &lt;base href=<span class="hljs-string">&quot;&lt;%=basePath%&gt;&quot;</span>&gt;<br>    &lt;title&gt;发起请求&lt;/title&gt;<br>&lt;/head&gt;<br>&lt;body&gt;<br>    &lt;form action=<span class="hljs-string">&quot;test.do&quot;</span>&gt;<br>        &lt;table&gt;<br>            &lt;tr&gt;<br>                &lt;td&gt;姓名：&lt;/td&gt;<br>                &lt;td&gt;&lt;input type=<span class="hljs-string">&quot;text&quot;</span> name=<span class="hljs-string">&quot;name&quot;</span>&gt;&lt;/td&gt;<br>            &lt;/tr&gt;<br>            &lt;tr&gt;<br>                &lt;td&gt;年龄：&lt;/td&gt;<br>                &lt;td&gt;&lt;input type=<span class="hljs-string">&quot;text&quot;</span> name=<span class="hljs-string">&quot;age&quot;</span>&gt;&lt;/td&gt;<br>            &lt;/tr&gt;<br>            &lt;tr&gt;<br>                &lt;td&gt;&lt;/td&gt;<br>                &lt;td&gt;&lt;input type=<span class="hljs-string">&quot;submit&quot;</span> value=<span class="hljs-string">&quot;发起请求&quot;</span>&gt;&lt;/td&gt;<br>            &lt;/tr&gt;<br>        &lt;/table&gt;<br>    &lt;/form&gt;<br>&lt;/body&gt;<br>&lt;/html&gt;<br></code></pre></td></tr></table></figure>

<p>响应页面 show.jsp </p>
<figure class="highlight jsp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs jsp">&lt;%@ page contentType=<span class="hljs-string">&quot;text/html;charset=UTF-8&quot;</span> language=<span class="hljs-string">&quot;java&quot;</span> %&gt;<br>&lt;%<br>    String basePath = request.getScheme() + <span class="hljs-string">&quot;://&quot;</span> + request.getServerName() + <span class="hljs-string">&quot;:&quot;</span> +    request.getServerPort() + request.getContextPath() + <span class="hljs-string">&quot;/&quot;</span>;<br>%&gt;<br>&lt;html&gt;<br>&lt;head&gt;<br>    &lt;base href=<span class="hljs-string">&quot;&lt;%=basePath%&gt;&quot;</span>&gt;<br>    &lt;title&gt;展示数据&lt;/title&gt;<br>&lt;/head&gt;<br>&lt;body&gt;<br>&lt;h2&gt;myName = $&#123;myName&#125;&lt;/h2&gt;<br>&lt;h2&gt;myAge = $&#123;myAge&#125;&lt;/h2&gt;<br>&lt;/body&gt;<br>&lt;/html&gt;<br></code></pre></td></tr></table></figure>



<h3 id="6-1-请求转发"><a href="#6-1-请求转发" class="headerlink" title="6.1 请求转发"></a>6.1 请求转发</h3><p>当我们指定了视图解析器，处理器方法最后要跳转的路径也符合视图解析器（即 show.jsp 在 /WEB-INF/view 目录下），我们可以直接使用 modelAndView.setViewName(“名称”);</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Controller</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyController</span> </span>&#123;<br><br>    <span class="hljs-meta">@RequestMapping(&quot;/test.do&quot;)</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> ModelAndView <span class="hljs-title">forwardTest</span><span class="hljs-params">(String name, String age)</span> </span>&#123;<br>        ModelAndView modelAndView = <span class="hljs-keyword">new</span> ModelAndView();<br>        modelAndView.addObject(<span class="hljs-string">&quot;myName&quot;</span>, name);<br>        modelAndView.addObject(<span class="hljs-string">&quot;myAge&quot;</span>, age);<br>        modelAndView.setViewName(<span class="hljs-string">&quot;show&quot;</span>);<br>        <span class="hljs-keyword">return</span> modelAndView;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>这是我们之前就在使用的。</p>
<p>但当我要转发是视图不在视图解析器解析中指定的路径下时，这种方法就不行了。</p>
<p>所以在处理器方法返回 ModelAndView 时，只要在 setViewName() 指定的视图前添加 <strong>forward:<strong>，此时的视图不再与视图解析器一同工作，这样可以在配置了解析器时指定不同位置的视图。</strong>视图页面必须写出相对于项目根的路径</strong>。forward 操作不需要视图解析器。</p>
<p><strong>另：处理器方法返回 String, 同时是为了跳转视图，在视图路径前面加入 forward: 视图完整路径。</strong></p>
<p>测试：将 show.jsp 放在 webapp 根目录下</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs xml">&lt;%@ page contentType=&quot;text/html;charset=UTF-8&quot; language=&quot;java&quot; %&gt;<br>&lt;%<br>    String basePath = request.getScheme() + &quot;://&quot; + request.getServerName() + &quot;:&quot; + 	request.getServerPort() + request.getContextPath() + &quot;/&quot;;<br>%&gt;<br><span class="hljs-tag">&lt;<span class="hljs-name">html</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">base</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&quot;&lt;%=basePath%&gt;&quot;</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>展示数据<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>webapp 下的 show.jsp<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>myName = $&#123;myName&#125;<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>myAge = $&#123;myAge&#125;<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span><br><br></code></pre></td></tr></table></figure>

<p>处理器方法</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Controller</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyController</span> </span>&#123;<br><br>    <span class="hljs-meta">@RequestMapping(&quot;/test.do&quot;)</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> ModelAndView <span class="hljs-title">test</span><span class="hljs-params">(String name, String age)</span> </span>&#123;<br>        ModelAndView modelAndView = <span class="hljs-keyword">new</span> ModelAndView();<br>        modelAndView.addObject(<span class="hljs-string">&quot;myName&quot;</span>, name);<br>        modelAndView.addObject(<span class="hljs-string">&quot;myAge&quot;</span>, age);<br>        modelAndView.setViewName(<span class="hljs-string">&quot;forward:/show.jsp&quot;</span>);<br>        <span class="hljs-keyword">return</span> modelAndView;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>测试：</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210721/image.n3xs5iui5jk.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<h3 id="6-2-重定向"><a href="#6-2-重定向" class="headerlink" title="6.2 重定向"></a>6.2 重定向</h3><p>和请求转发写法类似，也是忽略视图解析器的。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs java">modelAndView.setViewName(<span class="hljs-string">&quot;redirect:/show.jsp&quot;</span>);<br></code></pre></td></tr></table></figure>

<p>但此时 show.jsp 中是不能获取到数据的 </p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210721/image.4c2o12f7svi0.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p>这是因为重定向过程中浏览器发送了两次请求，我们在处理器方法中是将数据保存在第一次请求的 request 域中，但是 show.jsp 是从第二次请求的 request 域中获取数据的，因此不能获取到数据。</p>
<p>但我们可以观察测试的地址栏，发现请求路径后是存在参数传递的，这是 SpringMVC 做的工作，会将处理器方法中向 request 域中保存的值，以参数的形式带到重定向路径后面，作为请求参数。</p>
<p>因此我们就可以在 show.jsp 中接受参数</p>
<figure class="highlight jsp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs jsp">&lt;h2&gt;webapp 下的 show.jsp&lt;/h2&gt;<br>&lt;h2&gt;myName = $&#123;param.myName&#125;&lt;/h2&gt;<br>&lt;h2&gt;myAge = $&#123;param.myAge&#125;&lt;/h2&gt;<br></code></pre></td></tr></table></figure>

<p>其中 <code>$&#123;param.myName&#125;</code> 是等价于 <code>&lt;%=request.getParameter(&quot;myName&quot;)%&gt;</code> ，即从request 对象中获取参数</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210721/image.6n0vtf0qk0w0.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p>尝试访问一下 WEB-INF/view 下的 show.jsp</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs java">modelAndView.setViewName(<span class="hljs-string">&quot;redirect:/WEB-INF/view/show.jsp&quot;</span>);<br></code></pre></td></tr></table></figure>

<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210721/image.1ioer9j35l5s.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<blockquote>
<p>总结：</p>
<p>当返回值是 ModelAndView 是，可以在 setViewName() 方法参数前加上 <strong>forward:</strong> 和 <strong>redirect:<strong>，分别表示请求转发和重定向，此时访问的</strong>资源路径要写全</strong>，视图解析器配置不起作用。</p>
<p>当返回值是 String 时，同样在返回路径前加上 <strong>forward:</strong>  或 **redirect:**，资源路径写全。</p>
</blockquote>
<h2 id="7-异常处理"><a href="#7-异常处理" class="headerlink" title="7. 异常处理"></a>7. 异常处理</h2><p>一般在方法中出现异常，都是在方法中使用 try catch 捕捉异常或者直接抛出，在处理器方法中，只能直接处理掉。</p>
<p>一般项目异常处理要进行的操作：</p>
<ol>
<li>把发生的异常记录到数据库或者日志文件中。记录日志发生的时间、发生异常的方法、异常的内容。</li>
<li>发送通知。把异常的信息通过邮件、短信方式发送给相关人员。</li>
<li>给用户友好的提示</li>
</ol>
<p>当这些异常处理操作都写在方法的 catch 语句块中，就会使方法臃肿，业务和异常处理耦合在一起了，同时多个方法都要处理异常，写的时候也麻烦。</p>
<p>SpringMVC 中给出了解决办法。</p>
<p><strong>SpringMVC 框架采用的是统一的、全局的异常处理，把  Controller 中所有异常处理都集中于一个地方。</strong></p>
<p>采用的使用 AOP 思想，将业务逻辑和异常处理代码分开，实现代码解耦合。</p>
<p><strong>主要使用两个注解：</strong></p>
<ol>
<li><p><code>@ExceptionHandler</code>：</p>
<ul>
<li>使用注解@ExceptionHandler 可以将一个方法指定为异常处理方法。该注解只有一个可选属性 value，为一个 Class&lt;? extends Throwable&gt;数组，用于指定该注解的方法所要处理的异常类，即所要匹配的异常。</li>
<li>被注解的方法，其返回值可以是 ModelAndView、String，或 void，方法名随意，方法参数可以是 Exception 及其子类对象、HttpServletRequest、HttpServletResponse 等。系统会自动为这些方法参数赋值。</li>
</ul>
</li>
<li><p><code>@ControllerAdvice</code>：</p>
<ul>
<li><p>异常处理方法会专门定义在一个类中，作为全局的异常处理类。此时这个类就需要 @ControllerAdvice 注解。</p>
</li>
<li><p>@ControllerAdvice，字面理解就是“控制器增强”，是给控制器对象增强功能的。使用 @ControllerAdvice 修饰的类中可以使用 @ExceptionHandler。当使用 @RequestMapping 注解修饰的方法抛出异常时，会执行@ControllerAdvice 修饰的类中的异常处理方法。</p>
</li>
<li><p>由于 @ControllerAdvice 是使用 @Component 注解修饰的，需要为修饰的类所在的包加入组件扫描。</p>
</li>
</ul>
</li>
</ol>
<p><strong>一个小例子</strong></p>
<p>项目结构</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210721/image.3vaamvp6r3s0.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p>springmvc-servlet.xml</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-comment">&lt;!-- 组件扫描 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">context:component-scan</span> <span class="hljs-attr">base-package</span>=<span class="hljs-string">&quot;cn.yechen.controller&quot;</span>/&gt;</span><br><span class="hljs-comment">&lt;!-- 指定注解 @ControllerAdvice 所在的包名 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">context:component-scan</span> <span class="hljs-attr">base-package</span>=<span class="hljs-string">&quot;cn.yechen.handler&quot;</span>/&gt;</span><br><br><span class="hljs-comment">&lt;!-- 视图解析器，指定视图位置和扩展名 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;org.springframework.web.servlet.view.InternalResourceViewResolver&quot;</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;prefix&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;/WEB-INF/view/&quot;</span>/&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;suffix&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;.jsp&quot;</span>/&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">bean</span>&gt;</span><br><br><span class="hljs-comment">&lt;!-- 注解驱动 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">mvc:annotation-driven</span>/&gt;</span><br></code></pre></td></tr></table></figure>

<p>请求页面 index.jsp</p>
<figure class="highlight jsp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><code class="hljs jsp">&lt;%@ page contentType=<span class="hljs-string">&quot;text/html;charset=UTF-8&quot;</span> language=<span class="hljs-string">&quot;java&quot;</span> %&gt;<br>&lt;%<br>    String basePath = request.getScheme() + <span class="hljs-string">&quot;://&quot;</span> + request.getServerName() + <span class="hljs-string">&quot;:&quot;</span> + 	request.getServerPort() + request.getContextPath() + <span class="hljs-string">&quot;/&quot;</span>;<br>%&gt;<br>&lt;html&gt;<br>&lt;head&gt;<br>    &lt;base href=<span class="hljs-string">&quot;&lt;%=basePath%&gt;&quot;</span>&gt;<br>    &lt;title&gt;发起请求&lt;/title&gt;<br>&lt;/head&gt;<br>&lt;body&gt;<br>&lt;form action=<span class="hljs-string">&quot;test.do&quot;</span>&gt;<br>    &lt;table&gt;<br>        &lt;tr&gt;<br>            &lt;td&gt;姓名：&lt;/td&gt;<br>            &lt;td&gt;&lt;input type=<span class="hljs-string">&quot;text&quot;</span> name=<span class="hljs-string">&quot;name&quot;</span>&gt;&lt;/td&gt;<br>        &lt;/tr&gt;<br>        &lt;tr&gt;<br>            &lt;td&gt;年龄：&lt;/td&gt;<br>            &lt;td&gt;&lt;input type=<span class="hljs-string">&quot;text&quot;</span> name=<span class="hljs-string">&quot;age&quot;</span>&gt;&lt;/td&gt;<br>        &lt;/tr&gt;<br>        &lt;tr&gt;<br>            &lt;td&gt;&lt;/td&gt;<br>            &lt;td&gt;&lt;input type=<span class="hljs-string">&quot;submit&quot;</span> value=<span class="hljs-string">&quot;发起请求&quot;</span>&gt;&lt;/td&gt;<br>        &lt;/tr&gt;<br>    &lt;/table&gt;<br>&lt;/form&gt;<br>&lt;/body&gt;<br>&lt;/html&gt;<br></code></pre></td></tr></table></figure>

<p>自定义异常</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserException</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Exception</span></span>&#123;<br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">UserException</span><span class="hljs-params">()</span> </span>&#123;<br>    &#125;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">UserException</span><span class="hljs-params">(String message)</span> </span>&#123;<br>        <span class="hljs-keyword">super</span>(message);<br>    &#125;<br>&#125;<br><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserNameException</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">UserException</span></span>&#123;<br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">UserNameException</span><span class="hljs-params">()</span> </span>&#123;<br>    &#125;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">UserNameException</span><span class="hljs-params">(String message)</span> </span>&#123;<br>        <span class="hljs-keyword">super</span>(message);<br>    &#125;<br>&#125;<br><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserAgeException</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">UserException</span> </span>&#123;<br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">UserAgeException</span><span class="hljs-params">()</span> </span>&#123;<br>    &#125;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">UserAgeException</span><span class="hljs-params">(String message)</span> </span>&#123;<br>        <span class="hljs-keyword">super</span>(message);<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>全局异常处理器 GlobalExceptionHandler.java</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">GlobalExceptionHandler</span> </span>&#123;<br><br>    <span class="hljs-comment">// 处理 UserException</span><br>    <span class="hljs-meta">@ExceptionHandler(UserException.class)</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> ModelAndView <span class="hljs-title">doUserException</span><span class="hljs-params">(UserException userException)</span> </span>&#123;<br>        ModelAndView modelAndView = <span class="hljs-keyword">new</span> ModelAndView();<br>        modelAndView.addObject(<span class="hljs-string">&quot;msg&quot;</span>, userException.getMessage());<br>        modelAndView.setViewName(<span class="hljs-string">&quot;userException&quot;</span>);<br>        <span class="hljs-keyword">return</span> modelAndView;<br>    &#125;<br><br>    <span class="hljs-comment">// 处理除 UserException 以外的异常</span><br>    <span class="hljs-meta">@ExceptionHandler</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> ModelAndView <span class="hljs-title">doOtherException</span><span class="hljs-params">(Exception exception)</span> </span>&#123;<br>        ModelAndView modelAndView = <span class="hljs-keyword">new</span> ModelAndView();<br>        modelAndView.addObject(<span class="hljs-string">&quot;msg&quot;</span>, exception.getMessage());<br>        modelAndView.setViewName(<span class="hljs-string">&quot;userException&quot;</span>);<br>        <span class="hljs-keyword">return</span> modelAndView;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<blockquote>
<p><strong>注</strong>：@ExceptionHandler 中 value 属性可以不写，但是只能出现一次，表示修饰方法处理没有指定的异常。如当前程序中，如果控制器抛出 UserException，则异常由 doUserException() 方法处理，控制器抛出其他异常，则由doOtherException() 方法处理。相当于一个擦屁股的方法。</p>
</blockquote>
<p>控制器 MyController.java，当 name 不为“张三”，年龄为 null 或者小于 18 时，主动抛出异常给控制器</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Controller</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyController</span> </span>&#123;<br><br>    <span class="hljs-meta">@RequestMapping(&quot;/test.do&quot;)</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> ModelAndView <span class="hljs-title">test</span><span class="hljs-params">(String name, Integer age)</span> <span class="hljs-keyword">throws</span> UserException </span>&#123;<br>        <span class="hljs-keyword">if</span> (!<span class="hljs-string">&quot;张三&quot;</span>.equals(name)) &#123;<br>            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> UserNameException(<span class="hljs-string">&quot;姓名不符合要求&quot;</span>);<br>        &#125;<br>        <span class="hljs-keyword">if</span> (age == <span class="hljs-keyword">null</span> || age &lt; <span class="hljs-number">18</span>) &#123;<br>            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> UserAgeException(<span class="hljs-string">&quot;年龄不符合要求&quot;</span>);<br>        &#125;<br>        ModelAndView modelAndView = <span class="hljs-keyword">new</span> ModelAndView();<br>        modelAndView.addObject(<span class="hljs-string">&quot;myName&quot;</span>, name);<br>        modelAndView.addObject(<span class="hljs-string">&quot;myAge&quot;</span>, age);<br>        modelAndView.setViewName(<span class="hljs-string">&quot;show&quot;</span>);<br>        <span class="hljs-keyword">return</span> modelAndView;<br>    &#125;<br><br>&#125;<br></code></pre></td></tr></table></figure>

<p>执行成功展示页面 show.jsp</p>
<figure class="highlight jsp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs jsp">&lt;%@ page contentType=<span class="hljs-string">&quot;text/html;charset=UTF-8&quot;</span> language=<span class="hljs-string">&quot;java&quot;</span> %&gt;<br>&lt;%<br>    String basePath = request.getScheme() + <span class="hljs-string">&quot;://&quot;</span> + request.getServerName() + <span class="hljs-string">&quot;:&quot;</span> + 	request.getServerPort() + request.getContextPath() + <span class="hljs-string">&quot;/&quot;</span>;<br>%&gt;<br>&lt;html&gt;<br>&lt;head&gt;<br>    &lt;base href=<span class="hljs-string">&quot;&lt;%=basePath%&gt;&quot;</span>&gt;<br>    &lt;title&gt;展示数据&lt;/title&gt;<br>&lt;/head&gt;<br>&lt;body&gt;<br>&lt;h2&gt;/WEB-INF/view 下的 show.jsp&lt;/h2&gt;<br>&lt;h2&gt;myName = $&#123;myName&#125;&lt;/h2&gt;<br>&lt;h2&gt;myAge = $&#123;myAge&#125;&lt;/h2&gt;<br>&lt;/body&gt;<br>&lt;/html&gt;<br></code></pre></td></tr></table></figure>

<p>抛出异常跳转页面 userException.jsp</p>
<figure class="highlight jsp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs jsp">&lt;%@ page contentType=<span class="hljs-string">&quot;text/html;charset=UTF-8&quot;</span> language=<span class="hljs-string">&quot;java&quot;</span> %&gt;<br>&lt;%<br>    String basePath = request.getScheme() + <span class="hljs-string">&quot;://&quot;</span> + request.getServerName() + <span class="hljs-string">&quot;:&quot;</span> + 	request.getServerPort() + request.getContextPath() + <span class="hljs-string">&quot;/&quot;</span>;<br>%&gt;<br>&lt;html&gt;<br>&lt;head&gt;<br>    &lt;base href=<span class="hljs-string">&quot;&lt;%=basePath%&gt;&quot;</span>&gt;<br>    &lt;title&gt;出错啦&lt;/title&gt;<br>&lt;/head&gt;<br>&lt;body&gt;<br>&lt;h2&gt;userException.jsp&lt;/h2&gt;<br>&lt;h2&gt;提示信息：$&#123;msg&#125;&lt;/h2&gt;<br>&lt;/body&gt;<br>&lt;/html&gt;<br></code></pre></td></tr></table></figure>

<p><strong>测试环节：</strong></p>
<p>正确输入：</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210721/image.12il3ma7zlnk.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210721/image.1radhhvzya00.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p>错误输入，抛出自定义异常：</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210721/image.5t3l7iwjoio0.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210721/image.2us3gw60o660.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p>错误输入，抛出其他异常：</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210721/image.633knb1ghlo0.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210721/image.50df6j061eo0.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<h2 id="8-拦截器"><a href="#8-拦截器" class="headerlink" title="8. 拦截器"></a>8. 拦截器</h2><p>SpringMVC 中的 <code>Interceptor 拦截器</code>是非常重要和相当有用的，它的主要作用是拦截指定的用户请求，并进行相应的预处理与后处理。</p>
<p>拦截器和过滤器类似，功能方向侧重点不同。 过滤器是用来<strong>过滤器请求参数</strong>，设置编码字符集等工作。拦截器是<strong>拦截用户的请求</strong>，对请求做判断处理的。</p>
<p>拦截器是全局的，可以对多个 Controller 做拦截。 一个项目中可以有任意数量的拦截器， 他们可以在一起拦截用户的请求。</p>
<p><strong>拦截器的执行时间：</strong></p>
<ol>
<li>在请求处理之前， 也就是处理器方法执行之前。</li>
<li>在处理器方法执行之后也会执行。</li>
<li>在请求处理完成后也会执行。</li>
</ol>
<p>在 SpringMVC 中自定义拦截器需要实现 <code>HandlerInterceptor</code> 接口，并实现其中的三个方法，这三个方法分别就在拦截器的三个执行时间执行。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">HandlerInterceptor</span> </span>&#123;	<br><br>   <span class="hljs-function"><span class="hljs-keyword">default</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">preHandle</span><span class="hljs-params">(HttpServletRequest request, HttpServletResponse response, Object handler)</span></span><br><span class="hljs-function">         <span class="hljs-keyword">throws</span> Exception </span>&#123;<br><br>      <span class="hljs-keyword">return</span> <span class="hljs-keyword">true</span>;<br>   &#125;<br><br>   <span class="hljs-function"><span class="hljs-keyword">default</span> <span class="hljs-keyword">void</span> <span class="hljs-title">postHandle</span><span class="hljs-params">(HttpServletRequest request, HttpServletResponse response, Object handler,</span></span><br><span class="hljs-params"><span class="hljs-function">         <span class="hljs-meta">@Nullable</span> ModelAndView modelAndView)</span> <span class="hljs-keyword">throws</span> Exception </span>&#123;<br>   &#125;<br><br>   <span class="hljs-function"><span class="hljs-keyword">default</span> <span class="hljs-keyword">void</span> <span class="hljs-title">afterCompletion</span><span class="hljs-params">(HttpServletRequest request, HttpServletResponse response, Object handler,</span></span><br><span class="hljs-params"><span class="hljs-function">         <span class="hljs-meta">@Nullable</span> Exception ex)</span> <span class="hljs-keyword">throws</span> Exception </span>&#123;<br>   &#125;<br><br>&#125;<br></code></pre></td></tr></table></figure>

<p>以上是 <code>HandlerInterceptor</code> 接口中定义的方法，都是默认的，可以不实现。下面来分析以下这几方法：</p>
<p><code>preHandle()</code> ：该方法在<strong>处理器方法执行之前执行</strong>。</p>
<ul>
<li><strong>返回值：</strong>为 boolean，若为 true，则紧接着会执行处理器方法，且会将 afterCompletion() 方法放入到一个专门的方法栈中等待执行，即若返回值是 true，则 afterCompletion() 方法就一定会配套执行；若返回值为 false，则不会在继续执行处理器方法，请求到此方法就截止了。</li>
<li><strong>参数：</strong> <code>Object handler</code> 表示被拦截的控制器对象。</li>
<li><strong>作用：</strong>在这个方法中可以获取请求的信息， 验证请求是否符合要求。可以验证用户是否登录， 验证用户是否有权限访问某个连接地址（url）。如果验证失败，可以截断请求，请求不能被处理。如果验证成功，可以放行请求，此时控制器方法才能执行。</li>
</ul>
<p><code>postHandle</code>：该方法在<strong>处理器方法执行完成之后执行</strong>。处理器方法若最终未被执行（preHandle() 方法返回值为 false），则该方法不会执行。</p>
<ul>
<li><strong>参数：</strong><code>ModelAndView modelAndView</code>是处理器方法的返回值，可以修改 ModelAndView 中的数据和视图，可以影响到最后的执行结果。</li>
<li><strong>作用：</strong> 主要是通过一些判断，对原来的执行结果做二次修正。</li>
</ul>
<p><code>afterCompletion</code>：当 preHandle() 方法返回为 true 时，会将该方法放到专门的方法栈中，等到对请求进行响应的所有工作完成之后才执行该方法。即该方法是在中央调度器渲染（数据填充）了响应页面之后执行的，此时对ModelAndView 再操作也对响应无济于事。</p>
<ul>
<li><strong>参数：</strong><code>Exception ex</code> 是程序中发生的异常。</li>
<li><strong>作用：</strong>一般做资源回收工作的， 程序请求过程中创建了一些对象，在这里可以删除，把占用的内存回收。</li>
</ul>
<h3 id="8-1-拦截器三个方法的执行顺序验证"><a href="#8-1-拦截器三个方法的执行顺序验证" class="headerlink" title="8.1 拦截器三个方法的执行顺序验证"></a>8.1 拦截器三个方法的执行顺序验证</h3><p>处理器</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyController</span> </span>&#123;<br>    <span class="hljs-meta">@RequestMapping(&quot;/test.do&quot;)</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> ModelAndView <span class="hljs-title">test</span><span class="hljs-params">()</span> </span>&#123;<br>        System.out.println(<span class="hljs-string">&quot;===执行了 MyController 处理器方法===&quot;</span>);<br>        ModelAndView modelAndView = <span class="hljs-keyword">new</span> ModelAndView();<br>        modelAndView.addObject(<span class="hljs-string">&quot;msg&quot;</span>, <span class="hljs-string">&quot;执行了处理器方法，转发到了 show.jsp&quot;</span>);<br>        modelAndView.setViewName(<span class="hljs-string">&quot;show&quot;</span>);<br>        <span class="hljs-keyword">return</span> modelAndView;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>拦截器</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyInterceptor</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">HandlerInterceptor</span> </span>&#123;<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">preHandle</span><span class="hljs-params">(HttpServletRequest request, HttpServletResponse response, Object handler)</span> <span class="hljs-keyword">throws</span> Exception </span>&#123;<br>        System.out.println(<span class="hljs-string">&quot;---执行了 MyInterceptor 拦截器的 preHandle() 方法---&quot;</span>);<br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">true</span>;<br>    &#125;<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">postHandle</span><span class="hljs-params">(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)</span> <span class="hljs-keyword">throws</span> Exception </span>&#123;<br>        System.out.println(<span class="hljs-string">&quot;---执行了 MyInterceptor 拦截器的 postHandle() 方法---&quot;</span>);<br>    &#125;<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">afterCompletion</span><span class="hljs-params">(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)</span> <span class="hljs-keyword">throws</span> Exception </span>&#123;<br>        System.out.println(<span class="hljs-string">&quot;---执行了 MyInterceptor 拦截器的 afterCompletion() 方法---&quot;</span>);<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>展示页面 show.jsp</p>
<figure class="highlight jsp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs jsp">&lt;%@ page contentType=<span class="hljs-string">&quot;text/html;charset=UTF-8&quot;</span> language=<span class="hljs-string">&quot;java&quot;</span> %&gt;<br>&lt;%<br>    String basePath = request.getScheme() + <span class="hljs-string">&quot;://&quot;</span> + request.getServerName() + <span class="hljs-string">&quot;:&quot;</span> +    request.getServerPort() + request.getContextPath() + <span class="hljs-string">&quot;/&quot;</span>;<br>%&gt;<br>&lt;html&gt;<br>&lt;head&gt;<br>    &lt;base href=<span class="hljs-string">&quot;&lt;%=basePath%&gt;&quot;</span>&gt;<br>    &lt;title&gt;展示数据&lt;/title&gt;<br>&lt;/head&gt;<br>&lt;body&gt;<br>&lt;h2&gt;/WEB-INF/view 下的 show.jsp&lt;/h2&gt;<br>&lt;h2&gt;转发过来的消息 = $&#123;msg&#125;&lt;/h2&gt;<br>&lt;/body&gt;<br>&lt;/html&gt;<br></code></pre></td></tr></table></figure>

<p><strong>要使用拦截器，还需要在 SpringMVC 配置文件中注册拦截器</strong></p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-comment">&lt;!-- 注册拦截器 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">mvc:interceptors</span>&gt;</span><br>    <span class="hljs-comment">&lt;!--声明第一个拦截器--&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">mvc:interceptor</span>&gt;</span><br>        <span class="hljs-comment">&lt;!--</span><br><span class="hljs-comment">		指定拦截的请求uri地址</span><br><span class="hljs-comment">              path：就是uri地址，可以使用通配符 **，** 表示任意的字符，文件或者多级目录和目录中的文件</span><br><span class="hljs-comment">        --&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">mvc:mapping</span> <span class="hljs-attr">path</span>=<span class="hljs-string">&quot;/**&quot;</span>/&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;cn.yechen.handler.MyInterceptor&quot;</span>/&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">mvc:interceptor</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">mvc:interceptors</span>&gt;</span><br></code></pre></td></tr></table></figure>

<p>测试：发送请求</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210721/image.3keb626ovfu0.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p>查看控制台输出，确实按照顺序依次执行</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210721/image.3ytbaxwd1ce0.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p>现在将 preHandle() 方法的返回值该为 false</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Override</span><br><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">preHandle</span><span class="hljs-params">(HttpServletRequest request, HttpServletResponse response, Object handler)</span> <span class="hljs-keyword">throws</span> Exception </span>&#123;<br>    System.out.println(<span class="hljs-string">&quot;---执行了 MyInterceptor 拦截器的 preHandle() 方法---&quot;</span>);<br>    <span class="hljs-keyword">return</span> <span class="hljs-keyword">false</span>;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>发起请求，页面无内容</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210721/image.fxv41rhljxs.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p>控制台输出说明只执行了 preHandle() 方法，控制器方法没有执行，请求被拦截了。</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210721/image.2znr7z1bdsa0.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p>总结：拦截器中方法与处理器方法的执行顺序如下图</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210721/image.3ujexj0vw7g0.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p>换一种表现方式，也可以这样理解：</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210721/image.e59sbd7xv68.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<h3 id="8-2-多个拦截器"><a href="#8-2-多个拦截器" class="headerlink" title="8.2 多个拦截器"></a>8.2 多个拦截器</h3><p>以两个拦截器为例，多个也类似。</p>
<p>在添加一个拦截器，实现 <code>HandlerInterceptor</code> 接口，实现三个方法，将连个拦截器的 preHandle() 方法返回值都设为 true</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyInterceptor2</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">HandlerInterceptor</span> </span>&#123;<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">preHandle</span><span class="hljs-params">(HttpServletRequest request, HttpServletResponse response, Object handler)</span> <span class="hljs-keyword">throws</span> Exception </span>&#123;<br>        System.out.println(<span class="hljs-string">&quot;***执行了 MyInterceptor2 拦截器的 preHandle() 方法***&quot;</span>);<br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">true</span>;<br>    &#125;<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">postHandle</span><span class="hljs-params">(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)</span> <span class="hljs-keyword">throws</span> Exception </span>&#123;<br>        System.out.println(<span class="hljs-string">&quot;***执行了 MyInterceptor2 拦截器的 postHandle() 方法***&quot;</span>);<br>    &#125;<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">afterCompletion</span><span class="hljs-params">(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)</span> <span class="hljs-keyword">throws</span> Exception </span>&#123;<br>        System.out.println(<span class="hljs-string">&quot;***执行了 MyInterceptor2 拦截器的 afterCompletion() 方法***&quot;</span>);<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyInterceptor</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">HandlerInterceptor</span> </span>&#123;<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">preHandle</span><span class="hljs-params">(HttpServletRequest request, HttpServletResponse response, Object handler)</span> <span class="hljs-keyword">throws</span> Exception </span>&#123;<br>        System.out.println(<span class="hljs-string">&quot;---执行了 MyInterceptor 拦截器的 preHandle() 方法---&quot;</span>);<br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">false</span>;<br>    &#125;<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">postHandle</span><span class="hljs-params">(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)</span> <span class="hljs-keyword">throws</span> Exception </span>&#123;<br>        System.out.println(<span class="hljs-string">&quot;---执行了 MyInterceptor 拦截器的 postHandle() 方法---&quot;</span>);<br>    &#125;<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">afterCompletion</span><span class="hljs-params">(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)</span> <span class="hljs-keyword">throws</span> Exception </span>&#123;<br>        System.out.println(<span class="hljs-string">&quot;---执行了 MyInterceptor 拦截器的 afterCompletion() 方法---&quot;</span>);<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>在配置文件中注册这个拦截器</p>
<p><strong>注：拦截器的执行顺序就是按照配置文件中的注册是顺序，拦截器在容器内部保存在一个 List 集合中。</strong></p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-comment">&lt;!-- 注册拦截器 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">mvc:interceptors</span>&gt;</span><br>    <span class="hljs-comment">&lt;!-- 第一个拦截器 --&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">mvc:interceptor</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">mvc:mapping</span> <span class="hljs-attr">path</span>=<span class="hljs-string">&quot;/**&quot;</span>/&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;cn.yechen.handler.MyInterceptor&quot;</span>/&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">mvc:interceptor</span>&gt;</span><br>    <span class="hljs-comment">&lt;!-- 第二个拦截器 --&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">mvc:interceptor</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">mvc:mapping</span> <span class="hljs-attr">path</span>=<span class="hljs-string">&quot;/**&quot;</span>/&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;cn.yechen.handler.MyInterceptor2&quot;</span>/&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">mvc:interceptor</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">mvc:interceptors</span>&gt;</span><br></code></pre></td></tr></table></figure>

<p>发起请求，请求成功</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210721/image.77hlakj0g4w0.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p>观察控制台输出</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210721/image.5iip7irdsxs.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p>保持拦截器 1 preHandle() 方法返回值为 true，将拦截器 2 的 preHandle() 方法返回值改为 false，</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-comment">// 拦截器 1</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyInterceptor</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">HandlerInterceptor</span> </span>&#123;<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">preHandle</span><span class="hljs-params">(HttpServletRequest request, HttpServletResponse response, Object handler)</span> <span class="hljs-keyword">throws</span> Exception </span>&#123;<br>        System.out.println(<span class="hljs-string">&quot;---执行了 MyInterceptor 拦截器的 preHandle() 方法---&quot;</span>);<br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">true</span>;<br>    &#125;<br>&#125;<br><br><span class="hljs-comment">// 拦截器 2</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyInterceptor2</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">HandlerInterceptor</span> </span>&#123;<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">preHandle</span><span class="hljs-params">(HttpServletRequest request, HttpServletResponse response, Object handler)</span> <span class="hljs-keyword">throws</span> Exception </span>&#123;<br>        System.out.println(<span class="hljs-string">&quot;***执行了 MyInterceptor2 拦截器的 preHandle() 方法***&quot;</span>);<br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">false</span>;<br>    &#125;<br>&#125;    <br></code></pre></td></tr></table></figure>

<p>此时拦截器 2 会将处理器方法拦截，处理器方法不执行，在处理器方法之后执行的 postHandle() 方法也都不执行，但是由于在拦截器 1 preHandle() 方法返回 true 时，拦截器 1 的 afterCompletion() 方法就被放入到专门的方法栈中，在请求结束时还是会执行的</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210721/image.24tg1wph5ji.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p><strong>总结：</strong>当有多个拦截器时，形成拦<strong>截器链</strong>。拦截器链的执行顺序，与其注册顺序一致。</p>
<p>多个拦截器中方法与处理器方法的执行顺序如下图：</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210721/image.2l221nmxa2g0.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p>换一种表现方式，也可以这样理解：</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210721/image.70sgb9udy0g0.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p>从图中可以看出，只要有一个 preHandle() 方法返回 false，则上部的执行链将被断开，其后续的处理器方法与 postHandle() 方法都将无法执行。但，无论执行链执行情况怎样，只要方法栈中有方法，即执行链中只要有 preHandle() 方法返回 true，就会执行方法栈中的afterCompletion()方法。最终都会给出响应。</p>
<h3 id="8-3-使用拦截器完成防止用户恶意登录功能"><a href="#8-3-使用拦截器完成防止用户恶意登录功能" class="headerlink" title="8.3 使用拦截器完成防止用户恶意登录功能"></a>8.3 使用拦截器完成防止用户恶意登录功能</h3><p><strong>功能要求：</strong>编写一个登录页面（login.jsp），只有登录成功才能访问主页（index.jsp），未登录过的用户只能访问登录页面内，不能访问主页。</p>
<p><strong>实现：</strong>用户登录成功，将用户信息保存到 seesion 域中，只有 session 域中有用户信息，才能访问主页，否则跳转到登录页面继续登录。</p>
<p><strong>环境准备：</strong></p>
<p>项目结构：</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210722/image.fje1h3x0cew.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p>登录页面 login.jsp</p>
<figure class="highlight jsp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><code class="hljs jsp">&lt;%@ page contentType=<span class="hljs-string">&quot;text/html;charset=UTF-8&quot;</span> language=<span class="hljs-string">&quot;java&quot;</span> %&gt;<br>&lt;%<br>    String basePath = request.getScheme() + <span class="hljs-string">&quot;://&quot;</span> + request.getServerName() + <span class="hljs-string">&quot;:&quot;</span> + 	request.getServerPort() + request.getContextPath() + <span class="hljs-string">&quot;/&quot;</span>;<br>%&gt;<br>&lt;html&gt;<br>&lt;head&gt;<br>    &lt;base href=<span class="hljs-string">&quot;&lt;%=basePath%&gt;&quot;</span>&gt;<br>    &lt;title&gt;登录&lt;/title&gt;<br>&lt;/head&gt;<br>&lt;body&gt;<br>&lt;form action=<span class="hljs-string">&quot;login.do&quot;</span> method=<span class="hljs-string">&quot;get&quot;</span>&gt;<br>    &lt;table&gt;<br>        &lt;tr&gt;<br>            &lt;td&gt;姓名：&lt;/td&gt;<br>            &lt;td&gt;&lt;input type=<span class="hljs-string">&quot;text&quot;</span> name=<span class="hljs-string">&quot;name&quot;</span>&gt;&lt;/td&gt;<br>        &lt;/tr&gt;<br>        &lt;tr&gt;<br>            &lt;td&gt;密码：&lt;/td&gt;<br>            &lt;td&gt;&lt;input type=<span class="hljs-string">&quot;text&quot;</span> name=<span class="hljs-string">&quot;password&quot;</span>&gt;&lt;/td&gt;<br>        &lt;/tr&gt;<br>        &lt;tr&gt;<br>            &lt;td&gt;&lt;/td&gt;<br>            &lt;td&gt;&lt;span style=<span class="hljs-string">&quot;color: red&quot;</span>&gt;$&#123;exceptionMsg&#125;&lt;/span&gt;&lt;/td&gt;<br>        &lt;/tr&gt;<br>        &lt;tr&gt;<br>            &lt;td&gt;&lt;/td&gt;<br>            &lt;td&gt;&lt;input type=<span class="hljs-string">&quot;submit&quot;</span> value=<span class="hljs-string">&quot;登录&quot;</span>&gt;&lt;/td&gt;<br>        &lt;/tr&gt;<br>    &lt;/table&gt;<br>&lt;/form&gt;<br>&lt;/body&gt;<br>&lt;/html&gt;<br></code></pre></td></tr></table></figure>

<p>登录成功主页 index.jsp</p>
<figure class="highlight jsp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs jsp">&lt;%@ page contentType=<span class="hljs-string">&quot;text/html;charset=UTF-8&quot;</span> language=<span class="hljs-string">&quot;java&quot;</span> %&gt;<br>&lt;%<br>    String basePath = request.getScheme() + <span class="hljs-string">&quot;://&quot;</span> + request.getServerName() + <span class="hljs-string">&quot;:&quot;</span> + 	request.getServerPort() + request.getContextPath() + <span class="hljs-string">&quot;/&quot;</span>;<br>%&gt;<br>&lt;html&gt;<br>&lt;head&gt;<br>    &lt;base href=<span class="hljs-string">&quot;&lt;%=basePath%&gt;&quot;</span>&gt;<br>    &lt;title&gt;主页&lt;/title&gt;<br>&lt;/head&gt;<br>&lt;body&gt;<br>&lt;h2&gt;登录成功，欢迎您【$&#123;name&#125;】&lt;/h2&gt;<br>&lt;a href=<span class="hljs-string">&quot;logout.do&quot;</span>&gt;退出登录&lt;/a&gt;<br>&lt;/body&gt;<br>&lt;/html&gt;<br></code></pre></td></tr></table></figure>

<p>登录异常类 LoginException.java</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">LoginException</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Exception</span></span>&#123;<br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">LoginException</span><span class="hljs-params">()</span> </span>&#123;<br>    &#125;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">LoginException</span><span class="hljs-params">(String message)</span> </span>&#123;<br>        <span class="hljs-keyword">super</span>(message);<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>控制器 LoginController.java</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Controller</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">LoginController</span> </span>&#123;<br><br>    <span class="hljs-comment">// 登录操作，登录成功在 session 中保存值</span><br>    <span class="hljs-meta">@RequestMapping(&quot;/login.do&quot;)</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> ModelAndView <span class="hljs-title">login</span><span class="hljs-params">(String name, String password, HttpSession session)</span> <span class="hljs-keyword">throws</span> LoginException </span>&#123;<br>        <span class="hljs-comment">// 判断用户名和密码是否符合要求，不符合就抛出异常</span><br>        <span class="hljs-keyword">if</span> (!<span class="hljs-string">&quot;张三&quot;</span>.equals(name)) &#123;<br>            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> LoginException(<span class="hljs-string">&quot;用户名不正确&quot;</span>);<br>        &#125;<br>        <span class="hljs-keyword">if</span> (!<span class="hljs-string">&quot;123&quot;</span>.equals(password)) &#123;<br>            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> LoginException(<span class="hljs-string">&quot;密码不正确&quot;</span>);<br>        &#125;<br>        <span class="hljs-comment">// 用户名密码争取，登录成功</span><br>        ModelAndView modelAndView = <span class="hljs-keyword">new</span> ModelAndView();<br>        session.setAttribute(<span class="hljs-string">&quot;userName&quot;</span>, name);<br>        modelAndView.addObject(<span class="hljs-string">&quot;name&quot;</span>, name);<br>        modelAndView.setViewName(<span class="hljs-string">&quot;/WEB-INF/view/index.jsp&quot;</span>);<br>        <span class="hljs-keyword">return</span> modelAndView;<br>    &#125;<br><br>    <span class="hljs-comment">// 获取详细信息，只有登录成功后才能访问</span><br>    <span class="hljs-meta">@RequestMapping(&quot;/detail.do&quot;)</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> ModelAndView <span class="hljs-title">getDetail</span><span class="hljs-params">()</span> </span>&#123;<br>        ModelAndView modelAndView = <span class="hljs-keyword">new</span> ModelAndView();<br>        modelAndView.addObject(<span class="hljs-string">&quot;detail&quot;</span>, <span class="hljs-string">&quot;获取了详细信息&quot;</span>);<br>        modelAndView.setViewName(<span class="hljs-string">&quot;/WEB-INF/view/detail.jsp&quot;</span>);<br>        <span class="hljs-keyword">return</span> modelAndView;<br>    &#125;<br><br>    <span class="hljs-comment">// 登出操作，清除 session</span><br>    <span class="hljs-meta">@RequestMapping(&quot;/logout.do&quot;)</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> ModelAndView <span class="hljs-title">logout</span><span class="hljs-params">(HttpSession session)</span> </span>&#123;<br>        <span class="hljs-comment">// 清除 session，返回到登录页面</span><br>        session.removeAttribute(<span class="hljs-string">&quot;userName&quot;</span>);<br>        ModelAndView modelAndView = <span class="hljs-keyword">new</span> ModelAndView();<br>        modelAndView.setViewName(<span class="hljs-string">&quot;/login.jsp&quot;</span>);<br>        <span class="hljs-keyword">return</span> modelAndView;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>全局异常处理类 GlobalExceptionHandler.java</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@ControllerAdvice</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">GlobalExceptionHandler</span> </span>&#123;<br><br>    <span class="hljs-comment">// 处理登录异常，重新跳转至登录页面</span><br>    <span class="hljs-meta">@ExceptionHandler(&#123;LoginException.class&#125;)</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> ModelAndView <span class="hljs-title">doLoginException</span><span class="hljs-params">(LoginException loginException)</span> </span>&#123;<br>        ModelAndView modelAndView = <span class="hljs-keyword">new</span> ModelAndView();<br>        <span class="hljs-keyword">if</span> (<span class="hljs-string">&quot;用户名不正确&quot;</span>.equals(loginException.getMessage())) &#123;<br>            modelAndView.addObject(<span class="hljs-string">&quot;exceptionMsg&quot;</span>, <span class="hljs-string">&quot;用户名不正确&quot;</span>);<br>        &#125; <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (<span class="hljs-string">&quot;密码不正确&quot;</span>.equals(loginException.getMessage())) &#123;<br>            modelAndView.addObject(<span class="hljs-string">&quot;exceptionMsg&quot;</span>, <span class="hljs-string">&quot;密码不正确&quot;</span>);<br>        &#125;<br>        <span class="hljs-comment">// 继续转发到 login.jsp</span><br>        modelAndView.setViewName(<span class="hljs-string">&quot;/login.jsp&quot;</span>);<br>        <span class="hljs-keyword">return</span> modelAndView;<br>    &#125;<br><br>    <span class="hljs-comment">// 处理其他异常</span><br>    <span class="hljs-meta">@ExceptionHandler</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> ModelAndView <span class="hljs-title">doOtherException</span><span class="hljs-params">(Exception exception)</span> </span>&#123;<br>        ModelAndView modelAndView = <span class="hljs-keyword">new</span> ModelAndView();<br>        modelAndView.addObject(<span class="hljs-string">&quot;exceptionMsg&quot;</span>, exception.getMessage());<br>        modelAndView.setViewName(<span class="hljs-string">&quot;/login.jsp&quot;</span>);<br>        <span class="hljs-keyword">return</span> modelAndView;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>拦截器 LoginInterceptor.java</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">LoginInterceptor</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">HandlerInterceptor</span> </span>&#123;<br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">preHandle</span><span class="hljs-params">(HttpServletRequest request, HttpServletResponse response, Object handler)</span> <span class="hljs-keyword">throws</span> Exception </span>&#123;<br><br>        <span class="hljs-comment">// 判断当前请求是不是登录操作 /login.do，是的话就放行</span><br>        <span class="hljs-keyword">if</span> (<span class="hljs-string">&quot;/login.do&quot;</span>.equals(request.getServletPath())) &#123;<br>            <span class="hljs-keyword">return</span> <span class="hljs-keyword">true</span>;<br>        &#125;<br><br>        <span class="hljs-comment">// 当前 Session 中没有 userName，表示没有登录过，拦截</span><br>        Object name = request.getSession().getAttribute(<span class="hljs-string">&quot;userName&quot;</span>);<br>        <span class="hljs-keyword">if</span> (name == <span class="hljs-keyword">null</span>) &#123;<br>            <span class="hljs-comment">// 重新跳转到登录页面</span><br>            request.setAttribute(<span class="hljs-string">&quot;exceptionMsg&quot;</span>, <span class="hljs-string">&quot;请重新登录&quot;</span>);<br>            request.getRequestDispatcher(<span class="hljs-string">&quot;/login.jsp&quot;</span>).forward(request, response);<br>            <span class="hljs-keyword">return</span> <span class="hljs-keyword">false</span>;<br>        &#125;<br><br>        <span class="hljs-comment">// 已经登录过了，放行</span><br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">true</span>;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>SpringMVC 配置文件</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-comment">&lt;!-- 控制器所在包组件扫描 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">context:component-scan</span> <span class="hljs-attr">base-package</span>=<span class="hljs-string">&quot;cn.yechen.controller&quot;</span>/&gt;</span><br><span class="hljs-comment">&lt;!-- 异常处理器所在包组件扫描 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">context:component-scan</span> <span class="hljs-attr">base-package</span>=<span class="hljs-string">&quot;cn.yechen.handler&quot;</span>/&gt;</span><br><br><span class="hljs-comment">&lt;!-- 注册拦截器 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">mvc:interceptors</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">mvc:interceptor</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">mvc:mapping</span> <span class="hljs-attr">path</span>=<span class="hljs-string">&quot;/**&quot;</span>/&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;cn.yechen.handler.LoginInterceptor&quot;</span>/&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">mvc:interceptor</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">mvc:interceptors</span>&gt;</span><br></code></pre></td></tr></table></figure>

<p>在 web.xml </p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-comment">&lt;!-- 配置欢迎页面 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">welcome-file-list</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">welcome-file</span>&gt;</span>/login.jsp<span class="hljs-tag">&lt;/<span class="hljs-name">welcome-file</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">welcome-file-list</span>&gt;</span><br><br><span class="hljs-comment">&lt;!-- 注册 DispatcherServlet --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">servlet</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">servlet-name</span>&gt;</span>springmvc<span class="hljs-tag">&lt;/<span class="hljs-name">servlet-name</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">servlet-class</span>&gt;</span>org.springframework.web.servlet.DispatcherServlet<span class="hljs-tag">&lt;/<span class="hljs-name">servlet-class</span>&gt;</span><br><br>    <span class="hljs-tag">&lt;<span class="hljs-name">init-param</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">param-name</span>&gt;</span>contextConfigLocation<span class="hljs-tag">&lt;/<span class="hljs-name">param-name</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">param-value</span>&gt;</span>classpath:springmvc-servlet.xml<span class="hljs-tag">&lt;/<span class="hljs-name">param-value</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">init-param</span>&gt;</span><br><br>    <span class="hljs-tag">&lt;<span class="hljs-name">load-on-startup</span>&gt;</span>1<span class="hljs-tag">&lt;/<span class="hljs-name">load-on-startup</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">servlet</span>&gt;</span><br><span class="hljs-comment">&lt;!-- 拦截动态资源和静态资源 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">servlet-mapping</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">servlet-name</span>&gt;</span>springmvc<span class="hljs-tag">&lt;/<span class="hljs-name">servlet-name</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">url-pattern</span>&gt;</span>/<span class="hljs-tag">&lt;/<span class="hljs-name">url-pattern</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">servlet-mapping</span>&gt;</span><br><br><span class="hljs-comment">&lt;!-- 配置 SpringMVC 中自带的乱码过滤器 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">filter</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">filter-name</span>&gt;</span>encoding<span class="hljs-tag">&lt;/<span class="hljs-name">filter-name</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">filter-class</span>&gt;</span>org.springframework.web.filter.CharacterEncodingFilter<span class="hljs-tag">&lt;/<span class="hljs-name">filter-class</span>&gt;</span><br>    <span class="hljs-comment">&lt;!-- 设置项目使用的字符编码 --&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">init-param</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">param-name</span>&gt;</span>encoding<span class="hljs-tag">&lt;/<span class="hljs-name">param-name</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">param-value</span>&gt;</span>utf-8<span class="hljs-tag">&lt;/<span class="hljs-name">param-value</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">init-param</span>&gt;</span><br>    <span class="hljs-comment">&lt;!-- 强制请求对象（HttpServletRequest）使用 encoding 编码的值 --&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">init-param</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">param-name</span>&gt;</span>forceRequestEncoding<span class="hljs-tag">&lt;/<span class="hljs-name">param-name</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">param-value</span>&gt;</span>true<span class="hljs-tag">&lt;/<span class="hljs-name">param-value</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">init-param</span>&gt;</span><br>    <span class="hljs-comment">&lt;!-- 强制响应对象（HttpServletResponse）使用 encoding 编码的值 --&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">init-param</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">param-name</span>&gt;</span>forceResponseEncoding<span class="hljs-tag">&lt;/<span class="hljs-name">param-name</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">param-value</span>&gt;</span>true<span class="hljs-tag">&lt;/<span class="hljs-name">param-value</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">init-param</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">filter</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">filter-mapping</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">filter-name</span>&gt;</span>encoding<span class="hljs-tag">&lt;/<span class="hljs-name">filter-name</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">url-pattern</span>&gt;</span>/*<span class="hljs-tag">&lt;/<span class="hljs-name">url-pattern</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">filter-mapping</span>&gt;</span><br></code></pre></td></tr></table></figure>

<p><strong>测试：</strong></p>
<ol>
<li>在没有登录的情况下直接访问 detail.do，发现被拦截器拦截，跳转到 login.jsp</li>
</ol>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210722/image.4k58g9b4c1w0.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<ol start="2">
<li>输入错误姓名、密码，被异常处理器处理，跳转到 login.jsp</li>
</ol>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210722/image.4vzvnkicyqo0.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<ol start="3">
<li>输入正确的姓名和密码，登录成功，跳转到 index.jsp</li>
</ol>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210722/image.2z081c7st2s0.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<ol start="4">
<li>登录成功后访问 detail.do，拦截器发现 session 中有值，放行，正常访问</li>
</ol>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210722/image.2yi7cttm1m00.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<ol start="5">
<li>在 index.jsp 点击登出按钮，清除 session，跳转到登录页面</li>
</ol>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210722/image.47anfj9870u0.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<ol start="6">
<li>再次访问 detail.do，此时 session 中没有值，拦截器拦截，不能访问</li>
</ol>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210722/image.7cst3xdzymk0.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<h2 id="参考文章"><a href="#参考文章" class="headerlink" title="参考文章"></a>参考文章</h2><p><a target="_blank" rel="noopener" href="https://www.cnblogs.com/ysocean/p/7375405.html">SpringMVC详解（二）——详细架构</a></p>
<p><a target="_blank" rel="noopener" href="https://blog.csdn.net/Number_oneEngineer/article/details/82775419?ops_request_misc=%7B%22request_id%22:%22162648934716780271556962%22,%22scm%22:%2220140713.130102334..%22%7D&request_id=162648934716780271556962&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_positive~default-1-82775419.pc_search_result_control_group&utm_term=springmvc&spm=1018.2226.3001.4187">SpringMVC框架介绍</a></p>
<p><a target="_blank" rel="noopener" href="https://blog.csdn.net/a745233700/article/details/80963758?ops_request_misc=%7B%22request_id%22:%22162648934716780271556962%22,%22scm%22:%2220140713.130102334..%22%7D&request_id=162648934716780271556962&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_positive~default-2-80963758.pc_search_result_control_group&utm_term=springmvc&spm=1018.2226.3001.4187">SpringMVC常见面试题总结（超详细回答）</a></p>
<p><a target="_blank" rel="noopener" href="https://blog.csdn.net/qq_33369905/article/details/106647313?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522162692364816780274147214%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=162692364816780274147214&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_positive~default-3-106647313.pc_search_all_es&utm_term=SpringMVC&spm=1018.2226.3001.4187">狂神说SpringMVC系列</a></p>

            </div>
            <hr>
            <div>
              <div class="post-metas mb-3">
                
                  <div class="post-meta mr-3">
                    <i class="iconfont icon-category"></i>
                    
                      <a class="hover-with-bg" href="/categories/SSM-%E6%A1%86%E6%9E%B6/">SSM 框架</a>
                    
                      <a class="hover-with-bg" href="/categories/SSM-%E6%A1%86%E6%9E%B6/SpringMVC/">SpringMVC</a>
                    
                  </div>
                
                
                  <div class="post-meta">
                    <i class="iconfont icon-tags"></i>
                    
                      <a class="hover-with-bg" href="/tags/SSM-%E6%A1%86%E6%9E%B6/">SSM 框架</a>
                    
                      <a class="hover-with-bg" href="/tags/SpringMVC/">SpringMVC</a>
                    
                  </div>
                
              </div>
              
                <p class="note note-warning">
                  
                    本博客所有文章除特别声明外，均采用 <a target="_blank" href="https://creativecommons.org/licenses/by-sa/4.0/deed.zh" rel="nofollow noopener noopener">CC BY-SA 4.0 协议</a> ，转载请注明出处！
                  
                </p>
              
              
                <div class="post-prevnext">
                  <article class="post-prev col-6">
                    
                    
                      <a href="/2021/09/13/JavaWeb-2021-09-13-EL%E8%A1%A8%E8%BE%BE%E5%BC%8F/">
                        <i class="iconfont icon-arrowleft"></i>
                        <span class="hidden-mobile">EL表达式</span>
                        <span class="visible-mobile">上一篇</span>
                      </a>
                    
                  </article>
                  <article class="post-next col-6">
                    
                    
                      <a href="/2021/09/13/SSM%E6%A1%86%E6%9E%B6-2021-09-13-MyBatis/">
                        <span class="hidden-mobile">MyBatis</span>
                        <span class="visible-mobile">下一篇</span>
                        <i class="iconfont icon-arrowright"></i>
                      </a>
                    
                  </article>
                </div>
              
            </div>

            
          </article>
        </div>
      </div>
    </div>
    
      <div class="d-none d-lg-block col-lg-2 toc-container" id="toc-ctn">
        <div id="toc">
  <p class="toc-header"><i class="iconfont icon-list"></i>&nbsp;目录</p>
  <div class="toc-body" id="toc-body"></div>
</div>

      </div>
    
  </div>
</div>

<!-- Custom -->


    

    
      <a id="scroll-top-button" href="#" role="button">
        <i class="iconfont icon-arrowup" aria-hidden="true"></i>
      </a>
    

    
      <div class="modal fade" id="modalSearch" tabindex="-1" role="dialog" aria-labelledby="ModalLabel"
     aria-hidden="true">
  <div class="modal-dialog modal-dialog-scrollable modal-lg" role="document">
    <div class="modal-content">
      <div class="modal-header text-center">
        <h4 class="modal-title w-100 font-weight-bold">搜索</h4>
        <button type="button" id="local-search-close" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body mx-3">
        <div class="md-form mb-5">
          <input type="text" id="local-search-input" class="form-control validate">
          <label data-error="x" data-success="v"
                 for="local-search-input">关键词</label>
        </div>
        <div class="list-group" id="local-search-result"></div>
      </div>
    </div>
  </div>
</div>
    

    
  </main>

  <footer class="text-center mt-5 py-3">
  <div class="footer-content">
     <a href="https://hexo.io" target="_blank" rel="nofollow noopener"><span>Hexo</span></a> <i class="iconfont icon-love"></i> <a href="https://github.com/fluid-dev/hexo-theme-fluid" target="_blank" rel="nofollow noopener"><span>Fluid</span></a> 
  </div>
  

  

  
</footer>


  <!-- SCRIPTS -->
  
  <script  src="https://cdn.jsdelivr.net/npm/nprogress@0.2.0/nprogress.min.js" ></script>
  <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/nprogress@0.2.0/nprogress.min.css" />

  <script>
    NProgress.configure({"showSpinner":false,"trickleSpeed":100})
    NProgress.start()
    window.addEventListener('load', function() {
      NProgress.done();
    })
  </script>


<script  src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js" ></script>
<script  src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/js/bootstrap.min.js" ></script>
<script  src="/js/events.js" ></script>
<script  src="/js/plugins.js" ></script>

<!-- Plugins -->


  
    <script  src="/js/img-lazyload.js" ></script>
  



  



  <script  src="https://cdn.jsdelivr.net/npm/tocbot@4.12.3/dist/tocbot.min.js" ></script>



  <script  src="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3.5.7/dist/jquery.fancybox.min.js" ></script>



  <script  src="https://cdn.jsdelivr.net/npm/anchor-js@4.3.1/anchor.min.js" ></script>



  <script defer src="https://cdn.jsdelivr.net/npm/clipboard@2.0.8/dist/clipboard.min.js" ></script>



  <script  src="/js/local-search.js" ></script>






  <script  src="https://cdn.jsdelivr.net/npm/typed.js@2.0.12/lib/typed.min.js" ></script>
  <script>
    (function (window, document) {
      var typing = Fluid.plugins.typing;
      var title = document.getElementById('subtitle').title;
      
      typing(title)
      
    })(window, document);
  </script>














  
<script src="//cdn.jsdelivr.net/gh/bynotes/texiao/source/js/xiaoxuehua.js"></script>
<script src="//cdn.jsdelivr.net/gh/bynotes/texiao/source/js/caidai.js"></script>
<script src="//cdn.jsdelivr.net/gh/bynotes/texiao/source/js/love.js"></script>
<script src="//cdn.jsdelivr.net/npm/aplayer/dist/APlayer.min.js"></script>
<script src="//cdn.jsdelivr.net/gh/metowolf/MetingJS@1.2/dist/Meting.min.js"></script>



<!-- 主题的启动项 保持在最底部 -->
<script  src="/js/boot.js" ></script>

  <!--动态线条背景-->
  <script type="text/javascript" color="70,119,184" opacity='1' zIndex="-2" count="200" src="//cdn.bootcss.com/canvas-nest.js/1.0.0/canvas-nest.min.js"></script>

<script src="/live2dw/lib/L2Dwidget.min.js?094cbace49a39548bed64abff5988b05"></script><script>L2Dwidget.init({"model":{"jsonPath":"/live2dw/assets/koharu.model.json"},"display":{"position":"left","width":200,"height":400},"mobile":{"show":false},"log":false,"pluginJsPath":"lib/","pluginModelPath":"assets/","pluginRootPath":"live2dw/","tagMode":false});</script></body>
</html>
